2016-04-03 6 views
0

サブクエリ1:避け "filesortレコード"

SELECT * from big_table 
where category = 'fruits' and name = 'apple' 
order by yyyymmdd desc 

説明:

table  | key   | extra 
big_table | name_yyyymmdd | using where 

は素晴らしい見えます!

サブクエリ2:

SELECT * from big_table 
where category = 'fruits' and (taste = 'sweet' or wildcard = '*') 
order by yyyymmdd desc 

は説明:

table  | key    | extra 
big_table | category_yyyymmdd | using where 

は素晴らしい見えます!今

私はUNIONとのそれらを組み合わせる場合:

SELECT * from big_table 
where category = 'fruits' and name = 'apple' 

UNION 

SELECT * from big_table 
where category = 'fruits' and (taste = 'sweet' or wildcard = '*') 

Order by yyyymmdd desc 

は説明:それはfilesortレコードを使用して、

table  | key  | extra 
big_table | name  | using index condition, using where 
big_table | category | using index condition 
UNION RESULT| NULL  | using temporary; using filesort 

あまりよくありません。

これは、より多くの複合化クエリのトリムダウンバージョンである、ここでbig_tableに関するいくつかの事実は以下のとおりです。

  • big_tableは10M +行
  • を持っている5つのユニークな「カテゴリ」の
  • がありあります。約10,000ユニークな「名前」の
  • 約10,000ユニークな「YYYYMMDD」の
  • 私はCを持っているがありますがあります5独特の「味」の
  • ですそれらのフィールドのそれぞれにreated単一インデックスとyyyymmdd_category_taste_nameのような複合idxがありますが、Mysqlはそれを使用していません。

答えて

0
SELECT * FROM big_table 
    WHERE category = 'fruits' 
     AND ( name = 'apple' 
      OR taste = 'sweet' 
      OR wildcard = '*') 
    ORDER BY yyyymmdd DESC 

そしてcategoryとを開始INDEX(catgory)か、いくつかのインデックスを持っていなくても動作する必要があります。ただし、テーブルの約20%以上がcategory = 'fruits'の場合、インデックスを無視してテーブルスキャンを行うことになります。 (あなたが唯一の5つのカテゴリーがあると言うので、私は、オプティマイザは正しくインデックスを避けるだろう疑う)

またはこの有益であるかもしれない:この順に、INDEX(category, yyyymmdd)

UNIONは、希望の順序で行をフェッチできなかったため、ソートを実行する必要がありました(ディスク上のメモリでも、それは不明です)。

複合インデックスINDEX(yyyymmdd, ...)を使用して 'filesort'を避けることができますが、yyyymmddの後の列は使用しません。

を開始するときは、WHEREの列を '='と比較してと開始します。その後、group byまたはorder byの範囲を1つ追加できます。 More details

UNIONは、多くの場合、遅いORを避けるための良い選択ですが、この場合には3つのインデックス

INDEX(category, name) 
INDEX(category, taste) 
INDEX(category, wildcard) 

、あなたがLIMITを追加しない限り、YYYYMMDDは役に立たないの追加が必要になります。

そして、クエリは次のようになります。

(SELECT * FROM big_table WHERE category = 'fruits' AND name = 'apple') 
UNION DISTINCT 
(SELECT * FROM big_table WHERE category = 'fruits' AND taste = 'sweet') 
UNION DISTINCT 
(SELECT * FROM big_table WHERE category = 'fruits' AND wildcard = '*') 
ORDER BY yyyymmdd DESC 

制限を追加することも、乱雑になります。次いで

(SELECT ... ORDER BY yyyymmdd DESC LIMIT 10) 
UNION DISTINCT 
(SELECT ... ORDER BY yyyymmdd DESC LIMIT 10) 
UNION DISTINCT 
(SELECT ... ORDER BY yyyymmdd DESC LIMIT 10) 
ORDER BY yyyymmdd DESC LIMIT 10 

端3つの複合インデックスのそれぞれのの最初のタックyyyymmdd、さらに悪いであろうオフセットの追加。

「カバーする」インデックスと「レイジールックアップ」の2つの方法が役に立ちますが、私はそれを疑っています。

さらに別の手法は、すべての単語を同じ列に置き、FULLTEXTインデックスを使用する方法です。しかし、これはいくつかの理由で問題があるかもしれません。

+0

もう1つのこと... "filesort"は悪ではありません。クエリの複雑さです。 –

0

また、これはUNION

SELECT * from big_table 
where 
    (category = 'fruits' and name = 'apple') 
    OR 
    (category = 'fruits' and (taste = 'sweet' or wildcard = '*') 
ORDER BY yyyymmdd desc; 
+0

私のクエリは最初はUNIONなしでしたが、何らかの理由で2番目の条件(ワイルドカード)で一致する行を見つけるのに時間がかかりました。 –

+0

QUERYの完全な説明を投稿してください。フィールドの味やワイルドカードにINDEX(COMPOSITE)が存在しない可能性があります –

関連する問題