私は、WordPressのWP_Query
クラスで生成された次のクエリを書くより良い方法を見つけようとしています。今は非常にです。MySQL。ワードプレス。 IN文を使用するとクエリが遅くなる
SELECT SQL_CALC_FOUND_ROWS wp_posts.*
FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
INNER JOIN wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id)
INNER JOIN wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id)
INNER JOIN wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id)
INNER JOIN wp_postmeta AS mt6 ON (wp_posts.ID = mt6.post_id)
INNER JOIN wp_postmeta AS mt7 ON (wp_posts.ID = mt7.post_id)
INNER JOIN wp_postmeta AS mt8 ON (wp_posts.ID = mt8.post_id)
WHERE 1=1 AND wp_posts.post_type = 'gemstone'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future' OR wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending' OR wp_posts.post_status = 'private')
AND (wp_postmeta.meta_key = 'gemstone_active_price'
AND (mt1.meta_key = 'gemstone_status' AND CAST(mt1.meta_value AS CHAR) = 'Available')
AND (mt2.meta_key = 'gemstone_length' AND CAST(mt2.meta_value AS DECIMAL(10,2)) BETWEEN '0' AND '9')
AND (mt3.meta_key = 'gemstone_width' AND CAST(mt3.meta_value AS DECIMAL(10,2)) BETWEEN '0' AND '9')
AND (mt4.meta_key = 'gemstone_depth' AND CAST(mt4.meta_value AS DECIMAL(10,2)) BETWEEN '0' AND '7')
AND (mt5.meta_key = 'gemstone_color' AND CAST(mt5.meta_value AS CHAR) IN ('L','K','J','I','H','G','F','E','D'))
AND (mt6.meta_key = 'gemstone_clarity' AND CAST(mt6.meta_value AS CHAR) IN ('I3','I2','I1','SI2','SI1','VS2','VVS2','VVS1','IF','FL'))
AND (mt7.meta_key = 'gemstone_weight' AND CAST(mt7.meta_value AS DECIMAL(10,2)) BETWEEN '0.67' AND '1.85')
AND (mt8.meta_key = 'gemstone_active_price' AND CAST(mt8.meta_value AS DECIMAL(10,2)) BETWEEN '960' AND '2300')
)
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value+0 ASC
LIMIT 0, 20
私はそれは大きな混乱のように見えるけど、私は、WHERE句(MT5とMT6上記)で2つのIN
文を持っていないとき、全体の事は非常に迅速に実行されます。問題は、IN
ステートメントの使用を避けるために、クエリを書く別の方法を理解するのにSQLをよく知っていないことです。何か案は?
UPDATE:ここ はそれが誰を助ける場合には、このクエリのEXPLAIN
出力されます。誰か他の考えがあれば、私は何でもできる。これで私は完全に困惑しました。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE wp_postmeta ref post_id,meta_key meta_key 768 const 2 Using where; Using temporary; Using filesort
1 SIMPLE mt1 ref post_id,meta_key post_id 8 db.wp_postmeta.post_id 2 Using where
1 SIMPLE mt2 ref post_id,meta_key post_id 8 db.mt1.post_id 2 Using where
1 SIMPLE mt3 ref post_id,meta_key post_id 8 db.wp_postmeta.post_id 2 Using where
1 SIMPLE mt4 ref post_id,meta_key post_id 8 db.mt2.post_id 2 Using where
1 SIMPLE mt5 ref post_id,meta_key post_id 8 db.wp_postmeta.post_id 2 Using where
1 SIMPLE mt6 ref post_id,meta_key post_id 8 db.wp_postmeta.post_id 2 Using where
1 SIMPLE mt7 ref post_id,meta_key post_id 8 db.mt3.post_id 2 Using where
1 SIMPLE mt8 ref post_id,meta_key post_id 8 db.wp_postmeta.post_id 2 Using where
1 SIMPLE wp_posts eq_ref PRIMARY,type_status_date PRIMARY 8 db.wp_postmeta.post_id 1 Using where
UPDATE 2:いくつかのより多くの実験をした後 、私はそれがこのクエリを遅くしているだけでIN()
文ではないことを実現しています。複数のIN()
と3つ以上のBETWEEN...AND...
ステートメントの組み合わせがパフォーマンスに劇的な影響を与えるようです。例えば
、私は最後の2つのAND
条項(彼らと4.9s対)をドロップする場合、クエリを約0.04sで実行される、または私はIN()
文で2つのAND
条項を削除した場合、それは0.04sで実行されます。これは、2つのクエリソリューションが最適かもしれないと思うようになりますが、WordPressのWP_Query
APIを使って実装する方法がわかりません。もし私がそうしたとしても、それはただ1つのクエリを実行してからフィルタリングするよりも早いでしょう結果はPHPを介して。
私はいくつかの場所でフィルタリングをデータベースに残さなければならないということを読んだので、PHPでフィルタリングするのは嫌です。ちなみに、違いがあれば、処理能力の高いコンピュータ(Intel i7、12 GB RAMなど)にあるlocalhost
WAMPサーバーのWordPress 3.3.1インストールでこれらのクエリを実行しています。
UPDATE 3: 私はあきらめとPHPを経由してそれらのためのクエリとフィルタからすべてのIN()
条項の削除について考えていたが、それはいくつかの深刻なドローバックを持っています。非効率的でコードの匂いがするだけでなく、私のページネーションを正しく制御することもできません。すべてがデータベースでフィルタリングされている場合は、LIMIT
句を使用してページネーションを処理できます。私がPHPでフィルターをかけると、どのオフセットに対してどれだけ多くの結果が返されるか分かりません。だから、すべてのフィルタリングは実際にデータベースで行う必要がありますが、問題はどうなるのでしょうか。誰にも私のために何か提案がありますか?追加情報は誰にも役立つだろうか?
UPDATE 4:これを解決するための私の検索で 、私はWordPressのコアのTracシステム(http://core.trac.wordpress.org/ticket/20134)での問題として、それを投稿しました。そこにある開発者の1人は、私がIN
を私のメタ・クエリーに使用しているもののメタデータの代わりにタクソノミーを使用しようと提案しました。私はそのアドバイスを受けて、パフォーマンスの向上を見ましたが、残念ながら、それほど十分ではありませんでした。古いクエリは実行に4秒以上かかり、分類法を使用すると1秒以上になりました。しかし、私は実際には4 IN
型節(元の2ではなく)が必要であることに気付きました。 2つの追加タクソノミー句を使用すると、クエリの実行に18秒以上かかります。だから、私は正方形に戻ってきた。私が持っていた考え(おそらく妄想的なことです)は、基準に合致する投稿が少なくて済むので、これは非常に遅くなる可能性があります。テスト目的のために、私はポストタイプ'gemstone'
を持つ3つのポストをデータベースに持っています。それはそれと関係がありますか?誰もが興味を持っている場合は
は、私の新しいSQLは次のようになります。
SELECT SQL_CALC_FOUND_ROWS wp_posts.*
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_relationships AS tt1 ON (wp_posts.ID = tt1.object_id)
INNER JOIN wp_term_relationships AS tt2 ON (wp_posts.ID = tt2.object_id)
INNER JOIN wp_term_relationships AS tt3 ON (wp_posts.ID = tt3.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
INNER JOIN wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id)
INNER JOIN wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id)
INNER JOIN wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id)
INNER JOIN wp_postmeta AS mt6 ON (wp_posts.ID = mt6.post_id)
WHERE 1=1
AND (wp_term_relationships.term_taxonomy_id IN (71,72,73,74)
AND tt1.term_taxonomy_id IN (89,90,91,92,93,95,96,97)
AND tt2.term_taxonomy_id IN (56,50,104,53)
AND tt3.term_taxonomy_id IN (59,60,62)
)
AND wp_posts.post_type = 'gemstone'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future' OR wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending' OR wp_posts.post_status = 'private')
AND (wp_postmeta.meta_key = 'gemstone_weight'
AND (mt1.meta_key = 'gemstone_status' AND CAST(mt1.meta_value AS CHAR) = 'Available')
AND (mt2.meta_key = 'gemstone_length' AND CAST(mt2.meta_value AS DECIMAL(8,2)) BETWEEN '0' AND '9')
AND (mt3.meta_key = 'gemstone_width' AND CAST(mt3.meta_value AS DECIMAL(8,2)) BETWEEN '0' AND '9')
AND (mt4.meta_key = 'gemstone_depth' AND CAST(mt4.meta_value AS DECIMAL(8,2)) BETWEEN '0' AND '7')
AND (mt5.meta_key = 'gemstone_weight' AND CAST(mt5.meta_value AS DECIMAL(8,2)) BETWEEN '0.81' AND '1.81')
AND (mt6.meta_key = 'gemstone_active_price' AND CAST(mt6.meta_value AS DECIMAL(8,2)) BETWEEN '1083.9' AND '2078.26')
)
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value+0 ASC
LIMIT 0, 20
と新しいEXPLAIN
出力は次のとおりです。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE wp_postmeta ref post_id,meta_key meta_key 768 const 3 Using where; Using temporary; Using filesort
1 SIMPLE tt3 ref PRIMARY,term_taxonomy_id PRIMARY 8 db.wp_postmeta.post_id 1 Using where; Using index
1 SIMPLE tt2 ref PRIMARY,term_taxonomy_id PRIMARY 8 db.wp_postmeta.post_id 1 Using where; Using index
1 SIMPLE wp_term_relationships ref PRIMARY,term_taxonomy_id PRIMARY 8 db.tt2.object_id 1 Using where; Using index
1 SIMPLE wp_posts eq_ref PRIMARY,type_status_date PRIMARY 8 db.wp_postmeta.post_id 1 Using where
1 SIMPLE tt1 ref PRIMARY,term_taxonomy_id PRIMARY 8 db.wp_posts.ID 1 Using where; Using index
1 SIMPLE mt5 ref post_id,meta_key post_id 8 db.wp_posts.ID 2 Using where
1 SIMPLE mt6 ref post_id,meta_key post_id 8 db.wp_posts.ID 2 Using where
1 SIMPLE mt1 ref post_id,meta_key post_id 8 db.mt5.post_id 2 Using where
1 SIMPLE mt2 ref post_id,meta_key post_id 8 db.mt1.post_id 2 Using where
1 SIMPLE mt3 ref post_id,meta_key post_id 8 db.tt2.object_id 2 Using where
1 SIMPLE mt4 ref post_id,meta_key post_id 8 db.tt3.object_id 2 Using where
UPDATE 5: のでコメントのを、私は最近optimizing this queryで別の刺し傷を取ったが、私はSQLがかなりセットアップされているという結論が残っていた。しかし、いくつかの選択肢をテストする際に、私は不思議なことに、クエリがより速く実行されることを発見しました。 MySQLサーバーを更新していないので、WordPressがパフォーマンスを向上させるためにデータベース構造を更新したということだけがわかります。アップデート4に表示されているのとまったく同じクエリは、現在約2.4秒かかります。私の意見ではまだまだ長すぎます(私はまだ私の答えに示されているようにSTRAIGHT_JOINを使用しています)が、改善に驚いています。ここに新しいEXPLAIN出力があります。それは私とほとんど同じですが、私はそれをどのように解釈するのか本当に分かりません。
+-----+--------------+------------------------+---------+---------------------------+-----------+----------+-------------------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+-----+--------------+------------------------+---------+---------------------------+-----------+----------+-------------------------------------+-------+----------------------------------------------+
| 1 | SIMPLE | wp_postmeta | ref | post_id,meta_key | meta_key | 768 | const | 5 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | wp_term_relationships | ref | PRIMARY,term_taxonomy_id | PRIMARY | 8 | db.wp_postmeta.post_id | 1 | Using where; Using index |
| 1 | SIMPLE | tt2 | ref | PRIMARY,term_taxonomy_id | PRIMARY | 8 | db.wp_term_relationships.object_id | 1 | Using where; Using index |
| 1 | SIMPLE | tt3 | ref | PRIMARY,term_taxonomy_id | PRIMARY | 8 | db.wp_term_relationships.object_id | 1 | Using where; Using index |
| 1 | SIMPLE | wp_posts | eq_ref | PRIMARY,type_status_date | PRIMARY | 8 | db.wp_postmeta.post_id | 1 | Using where |
| 1 | SIMPLE | tt1 | ref | PRIMARY,term_taxonomy_id | PRIMARY | 8 | db.wp_posts.ID | 1 | Using where; Using index |
| 1 | SIMPLE | mt3 | ref | post_id,meta_key | post_id | 8 | db.tt2.object_id | 3 | Using where |
| 1 | SIMPLE | mt4 | ref | post_id,meta_key | post_id | 8 | db.tt3.object_id | 3 | Using where |
| 1 | SIMPLE | mt5 | ref | post_id,meta_key | post_id | 8 | db.wp_posts.ID | 3 | Using where |
| 1 | SIMPLE | mt6 | ref | post_id,meta_key | post_id | 8 | db.wp_posts.ID | 3 | Using where |
| 1 | SIMPLE | mt1 | ref | post_id,meta_key | post_id | 8 | db.mt5.post_id | 3 | Using where |
| 1 | SIMPLE | mt2 | ref | post_id,meta_key | post_id | 8 | db.mt3.post_id | 3 | Using where |
+-----+--------------+------------------------+---------+---------------------------+-----------+----------+-------------------------------------+-------+----------------------------------------------+
アップデートとして。 phpMyAdminでプロファイリングをオンにしてこのクエリを実行すると、「統計」が経過した時間の99%を占めます。この文脈で「統計」が何を意味するか知っていますか? –
ここで説明したように、追加のINNER JOINを削除してみてください:http://stackoverflow.com/a/15398104/212076 – KalenGi