いくつかの結合を使用して各列を取得する(ビューを作成するための)クエリがあります。追加された結合のセットごとに、パフォーマンスが急速に(指数関数的に)低下します。
このクエリを高速化するには、どのようなアプローチが適切でしょうか?クエリ内のコメントを参照してください。
それが役立つ場合は、WordPress DBスキーマを使用しています。
EXPLAINのスクリーンショット
製品表
+--+----+
|id|name|
+--+----+
|1 |test|
+--+----+
メタデータテーブル
+----------+--------+-----+
|product_id|meta_key|value|
+----------+--------+-----+
|1 |price |9.99 |
+----------+--------+-----+
|1 |sku |ABC |
+----------+--------+-----+
TERM_RELATIONSHIPS TABLE
+---------+----------------+
|object_id|term_taxonomy_id|
+---------+----------------+
|1 |1 |
+---------+----------------+
|1 |2 |
+---------+----------------+
TERM_TAXONOMY TABLE
+----------------+-------+--------+
|term_taxonomy_id|term_id|taxonomy|
+----------------+-------+--------+
|1 |1 |size |
+----------------+-------+--------+
|2 |2 |stock |
+----------------+-------+--------+
用語表
+-------+-----+
|term_id|name |
+-------+-----+
|1 |500mg|
+-------+-----+
|2 |10 |
+-------+-----+
クエリ
SELECT
products.id,
products.name,
price.value AS price,
sku.value AS sku,
size.name AS size
FROM products
/* These joins are performing quickly */
INNER JOIN `metadata` AS price ON products.id = price.product_id AND price.meta_key = 'price'
INNER JOIN `metadata` AS sku ON products.id = sku.product_id AND sku.meta_key = 'sku'
/* Here's the part that is really slowing it down - I run this chunk about 5 times with different strings to match */
INNER JOIN `term_relationships` AS tr ON products.id = tr.object_id
INNER JOIN `term_taxonomy` AS tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'size'
INNER JOIN `terms` AS size
ON tt.term_id = size.term_id
パフォーマンスの問題は、おそらく 'term_taxonomy'テーブルとの結合が原因です。
他のすべての結合は、主キーを使用しているようです(おそらく作業インデックスがある)。
だから私の提案は、複合インデックスをterm_taxonomy_idおよびterm_idに追加することです(または必要な場合はtaxonomy)。このような:
CREATE UNIQUE INDEX idx_term_taxonomy_id_taxonomy
ON term_taxonomy( term_taxonomy_id, taxonomy);
これがお役に立てば幸いです。
"ON"条件ステートメントが存在するすべての列にインデックスを付ける必要があることを確認してください。これにより、速度が大幅に向上します。
私はそれらを提案します:
私の経験では:
(私にあなたのクエリのパフォーマンスを改善するためのソリューションを提供しなかったことを許してください。)
METADATA_TABLEおよびTERM_RELATIONSHIP_TABLEには、proimaryキーはありません。これらのテーブルに巨大なレコードがある場合、クエリのパフォーマンスが低下します。
パフォーマンスを向上させるチェックポイント。
ただし、複数の挿入と更新が行われているテーブルでは、非クラスター化インデックスが非常に少なくなることに注意してください。これは単純な質問ではなく、実行時間だけに基づいて回答することはできません。特に、ストアドプロシージャが実行されている環境のトランザクションが多すぎる場合は、他にも回答に影響する要素があります。
あなたはもっと見つけることができます ここ
Declare @query as NVARCHAR(MAX)
set @query = ('SELECT
products.id,
products.name,
price.value AS price,
sku.value AS sku,
size.name AS size
FROM products
INNER JOIN metadata AS price ON products.id = price.product_id AND price.meta_key = price
INNER JOIN metadata AS sku ON products.id = sku.product_id AND sku.meta_key = sku
INNER JOIN term_relationships AS tr ON products.id = tr.object_id
INNER JOIN term_taxonomy AS tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = size
INNER JOIN terms AS size
ON tt.term_id = size.term_id
into #t')
exec(@query);
select * from #t
上記の方法で時間の使用率が減るか、または選択したすべてのフィールドを持つ一時テーブルを作成し、一時テーブルを他のすべてのテーブルに結合して一時テーブルを更新することも効果的であると思いますが、よくわかりませんしかし、あなたの質問が興味をそそられるように私はあなたの結果を待っています
以下のスクリプトは、SQL Serverルールに従ってフォーマットされています-これをMySQLルールに従って変更して、試してみることができます-
SELECT
P.id,
P.name,
PIVOT_METADATA.price,
PIVOT_METADATA.sku,
size.name AS size
FROM products P (NOLOCK)
INNER JOIN term_relationships AS tr (NOLOCK)
ON P.id = tr.object_id
INNER JOIN term_taxonomy AS tt (NOLOCK)
ON tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'size'
INNER JOIN terms AS size (NOLOCK)
ON tt.term_id = size.term_id
INNER JOIN METADATA (NOLOCK)
PIVOT
(
MAX(value)
FOR [meta_key] IN (price,sku)
)AS PIVOT_METADATA
ON P.id = PIVOT_METADATA.product_id
クエリでボトルネックになっていると思われるもの-メタデータに2回参加しています。テーブルには1対多の関係があるため、メタデータ2結合は害を及ぼしませんが、その後、より多くのテーブルを結合すると、1対多の関係が原因で行数が増加するため、パフォーマンスが低下します。
私が達成したこと-1対1の関係が可能な限り満たされるようにしています。これを行うために、メタデータのピボットを実行し、列として価格とSKUを作成しました。これで、私の製品IDのメタデータピボットに1行のみが含まれるようになります。 alos、私は最後にこのピコに参加することを確認しました。
試してみる。期待されるパフォーマンス、保有しているレコードの数、および私のパフォーマンスで得られるパフォーマンスを教えてください。
これを試して:
SELECT p.id, p.name, MAX(CASE m.meta_key WHEN 'price' THEN m.value ELSE '' END) AS price,
MAX(CASE m.meta_key WHEN 'sku' THEN m.value ELSE '' END) AS sku, s.name AS size
FROM products p
INNER JOIN `metadata` AS m ON p.id = m.product_id
INNER JOIN `term_relationships` AS tr ON p.id = tr.object_id
INNER JOIN `term_taxonomy` AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'size'
INNER JOIN `terms` AS s ON tt.term_id = s.term_id
GROUP BY p.id;
それでもクエリが遅い場合は、クエリのEXPLAIN
プランを追加して、どの列にINDEX
が必要かを見つけられるようにします。