2

私はこのクエリを持っています:

SELECT stringa FROM table WHERE stringb = 'x' OR stringb = 'y' OR stringb = 'z'

これは単なる短縮版です。実際のクエリには、1 つのクエリに 1,000 を超える「OR」句があります。

実行には数分かかりますが、これは良くありません。

私は次のように一度に1つのクエリを実行しようとしました:

SELECT stringa FROM table WHERE stringb = 'x'
SELECT stringa FROM table WHERE stringb = 'y'
SELECT stringa FROM table WHERE stringb = 'z'

しかし、それにはさらに時間がかかります。次のような大きなクエリも試しました。

SELECT stringa FROM table WHERE stringb = 'x'
UNION
SELECT stringa FROM table WHERE stringb = 'y'
UNION
SELECT stringa FROM table WHERE stringb = 'z'

しかし、それにはさらに時間がかかりました。

パフォーマンスを向上させるための提案があれば、大歓迎です。重要な場合、私のテーブルは MyISAM です。

編集:

テーブルの構造は次のとおりです。

列:

key (CHAR PRIMARY), stringa (CHAR), stringb (CHAR)

行は次のようになります: (key - stringa - stringb)

key - a - b
key - a - c
key - a - d
key - a - e
key - a - f
key - b - b
key - b - c
key - b - d
key - c - c
key - c - d
key - c - f
key - d - f

etc. etc. ..100万行近くあります。

「stringb」が a OR b OR c などに等しいすべての「stringa」を選択する必要があります。

もちろん、stringa と stringb は単なる 'a' と 'b' ではなく、3 ~ 80 文字の間で変化する長さの CHAR を含みます。

それが何らかの形で役立つことを願っています

4

5 に答える 5

2

まず、列のデータ型を に変更しますvarchar。おそらく高速であると聞いたことがあるかもしれませんがchar、トレードオフは、I/O の大幅な増加のために CPU をわずかに節約することです (非常に悪いトレードです)。

stringb次に、列にまだインデックスがない場合は、列にインデックスが必要です。インデックスは一意である必要はありません。

第三に、多くの DBMS では何千もの OR 条件を使用しても問題ありませんが、通常は のように表現されWHERE stringb IN ('a', 'b', 'c', 'd', 'e' ...)ます。

最後に、多くの場合、JOIN は、優れたパフォーマンスを提供しない場合でも (一部の DBMS または状況では可能ですが)、少なくともより明確になり、再利用できます。たとえば、多くの人が行っていることの 1 つは、文字列分割関数を作成することです。この関数は、形式で文字列を渡すと、'a,b,c,d,e'各項目を個別の行に含む行セットを返します。この行セットへの結合は簡単です。クライアントが分割する文字列を構築できる限り、クエリを動的に駆動できるようになります。

JOIN を実行する方法の 1 つを次に示します。

CREATE TEMPORARY TABLE Keys (
   Value varchar(30)
);

INSERT Keys VALUES ('x');
INSERT Keys VALUES ('y');
INSERT Keys VALUES ('z');

SELECT T.SomeColumns
FROM
   YourTable T
   INNER JOIN Keys K
      ON T.stringb = K.Value
于 2012-08-03T21:35:00.747 に答える
1

まず、他の人が示唆しているように、このデータにはCHARよりもVARCHARの方が適しています。CHAR は速くなりません。

KEY(stringb) PARTITIONS 8 (これは任意です) でテーブルを分割し、(stringb,stringa) にインデックスを追加することを検討してください。これにより IO が削減され、カバリング インデックスによってデータが返される速度が速くなります。

IN PARALLEL で等価ルックアップを実行します。ランニング:

SELECT stringa FROM table WHERE stringb  in('x',...)
SELECT stringa FROM table WHERE stringb  in('y',...)
SELECT stringa FROM table WHERE stringb  in('z',...)

3 つのスレッドでは、パフォーマンスが大幅に向上します。

結果を元に戻すだけで済みますが、これは難しくありません。Shard-Query を使用して、調べたい場合は IN() リストを使用してクエリを自動的に並列化できます。

http://code.google.com/p/shard-query

于 2012-08-04T01:44:16.190 に答える
1

stringb 列にインデックスを作成する必要があります。

あなたの問題は、「または」の効率ではなく、完全なテーブルスキャンを行っていることです。「in」ステートメントで値のリストをルーティングするのが伝統的です。ただし、一部のデータベースでは、これはパフォーマンスに影響しません。

また、フィールドは char または varchar で宣言されていますか? それらが char の場合、それがおそらくパフォーマンスの問題の原因です。これらはスペースで埋められ、ストレージのフットプリントが大幅に増加し、比較が長くなります.

于 2012-08-03T22:02:20.257 に答える
0

試す

SELECT stringa FROM table WHERE stringb = 'x' 
UNION ALL
SELECT stringa FROM table WHERE stringb = 'y' 
UNION ALL
SELECT stringa FROM table WHERE stringb = 'z' 

また

SELECT stringa FROM table WHERE stringb in ( 'x', 'y', 'z')

または、本当に千のOR条件がある場合は@ErikEのソリューション。

UNION ALL は、選択が相互に排他的であるため、UNON よりもかなり高速である必要があります。ユニオンのようにクエリを削除する必要はありません。

于 2012-08-03T22:12:00.563 に答える
0

@HLGEM の 2 番目の回答が最適だと思いますが、列 stringb のクエリで正規表現を使用することもできます。

于 2012-08-03T23:09:42.517 に答える