MySQL の (ビットごとの) スーパーセットとサブセット
-
12-09-2019 - |
質問
次のクエリは MySQL で有効ですか:
SELECT * FROM table WHERE field & number = number;
# to find values with superset of number's bits
SELECT * FROM table WHERE field | number = number;
# to find values with subset of number's bits
...フィールドのインデックスが作成されているかどうか?
そうでない場合、より速く実行する方法はありますか?
解決
アップデート:
パフォーマンスの詳細については、私のブログのこのエントリを参照してください。
SELECT * FROM table WHERE field & number = number
SELECT * FROM table WHERE field | number = number
このインデックスは次の 2 つの方法で効果を発揮します。
- 早期のテーブル スキャンを回避するため (比較する値がインデックス自体に含まれているため)
- 検査される値の範囲を制限します。
上記のクエリのどちらの条件も 検索可能な, 、これは範囲スキャンに使用されないインデックスです (現在の条件で)。
ただし、ポイント 1
は今でも保持されており、インデックスは役立つ可能性があります。
テーブルに次のものが含まれているとします。 100
行あたりの平均バイト数、および 1,000,000
レコードがある場合、テーブル スキャンでスキャンする必要があります。 100 Mb
データの。
インデックスがある場合 ( 4
-バイトキー、 6
-バイト行ポインターと一部の内部オーバーヘッド)、クエリはスキャンのみを必要とします。 10 Mb
のデータと、フィルターが成功した場合のテーブルからの追加データ。
- 条件が選択的でない場合 (条件に一致する可能性が高い場合)、テーブル スキャンはより効率的です。
- 条件が選択的である (条件に一致する確率が低い) 場合、インデックス スキャンはより効率的です。
これらのクエリはどちらもインデックス全体をスキャンする必要があります。
しかし、書き換えることによって、 AND
クエリでは、インデックスの範囲からも恩恵を受けることができます。
この条件:
field & number = number
の最上位ビットが一致する場合にのみフィールドと一致します。 number
セットは field
あまりにも。
そして、クエリに次の追加条件を指定するだけです。
SELECT *
FROM table
WHERE field & number = number
AND field >= 0xFFFFFFFF & ~((2 << FLOOR(LOG(2, 0xFFFFFFFF & ~number))) - 1)
これにより、粗いフィルタリングには範囲が使用され、細かいフィルタリングには条件が使用されます。
ビット数が多いほど、 number
最後に設定されていないほど良いです。
他のヒント
私は、オプティマイザはその1を理解ことはないだろう...
たぶん、あなたはこれらのクエリにEXPLAINを呼び出して、私の悲観的な推測を確認することができます。 (特定のデータベースの特定のインスタンスに基づいてクエリプランの決定の多くもちろん覚え、明確な計画を生成することができる異なる統計的プロファイルを有する、すなわち、可変データの量および/鉱石単にデータ)。
テーブルは、行のかなりの量を持っていること、及び「ビット単位」基準がINコンストラクトでクエリを書き換えることにより、すべての単一の行にビット演算を回避可能な場合、最適化が達成される)十分な選択のままであると仮定すると(またはJOINによる)
のようなもの(すなわち、テストされていない、概念)
CREATE TEMPORARY TABLE tblFieldValues
(Field INT);
INSERT INTO tblFieldValues
SELECT DISTINCT Field
FROM table;
-- SELECT * FROM table WHERE field | number = number;
-- now becomes
SELECT *
FROM table t
WHERE field IN
(SELECT Field
FROM tblFieldValues
WHERE field | number = number);
異なるユースケースで評価するために、この必要性のようなアプローチの利点をフル(すべてのテーブルの行のかなりの数がいるの、それ以外の場合は直接「フィールド|数=数」以来のアプローチは十分に効率的です)、私はこれはかなり速くなる可能性が疑われます。 「tblFieldValues」は毎回再作成する必要がない場合、さらに利益を達成することができます。もちろん、この表の効率的な作成は、元のテーブルのフィールドにインデックスを意味します。
私はこれを自分で試してみた、とビット演算は、「フィールド」の列にインデックスを使用してからMySQLを防ぐのに十分ではありません。これは、インデックスのフルスキャンが行われていること、しかし、可能性があります。