2

私のクエリは現在約3秒かかりますが、これは最適化できると確信しています。私はそれを最適化する方法を理解することができません。

私のアプリにはかなり大きなproductsテーブルがあります(約500,000レコード)。各製品は、50のドメインの1つにリストできます(表にリストされていdomainsます)。製品とドメイン間のリンクは、domains_productsテーブル(約1,400,000レコード)に格納されます。遅いクエリは私のアプリの管理セクションにあり、どのドメインにもリストされていない製品を表示できるようにする必要があります。

関係のないすべての結合を削除して、必要最低限​​の要素を削除すると、問題のクエリは次のようになります。

SELECT    `products`.*
FROM      `products`
LEFT JOIN `domains_products`
ON        `domains_products`.`product_id` = `products`.`id`
WHERE     `products`.`deleted` = 'N'
AND       `domains_products`.`domain_id` IS NULL
ORDER BY  `products`.`id` ASC

このフォームでは、クエリに3秒以上かかり、3,000を少し超える商品が返されます(これは正しいです)。いずれかWHEREの句を削除すると、クエリに0.12秒かかります(ただし、明らかに正しい結果が返されません)。

どちらのテーブルもInnoDBエンジンを使用しています。productsテーブルには、列に主キーがあり、列idにインデックスがありdeletedます。domains_productsテーブルにはと列のみがあり、product_iddomain_idキーはこれらの両方の列にあり、両方に独自のインデックスがあります。関連するすべての列はNOT NULL列です。

EXPLAIN私にこれを与えます:

id select_type table            type possible_keys key        key_len ref         rows   Extra
1  SIMPLE      products         ref  deleted       deleted    1       const       188616 Using where
1  SIMPLE      domains_products ref  product_id    product_id 4       products.id 1      Using where; Using index; Not exists

MySQLは正しいキーを検出しましたが、実際にはそれらを使用していないように見えることに注意してください。

プロファイラーはこれを言います:

Status               Time
Starting             62 µs
Checking Permissions 7 µs
Checking Permissions 5 µs
Opening Tables       38 µs
System Lock          13 µs
Init                 37 µs
Optimizing           17 µs
Statistics           1,3 ms
Preparing            25 µs
Executing            5 µs
Sorting Result       5 µs
Sending Data         3,3 s
End                  28 µs
Query End            8 µs
Closing Tables       25 µs
Freeing Items        297 µs
Logging Slow Query   4 µs
Cleaning Up          5 µs

に掛かっているようですのでご注意くださいSending Data。結合をNOTINに置き換えてみました:

SELECT `products`.*
FROM   `products`
WHERE  `products`.`deleted` = 'N'
AND    `product`.`id` NOT IN (
    SELECT `product_id`
    FROM   `domains_products`
)
ORDER BY `products`.`id` ASC

このクエリではまったく同じ結果が得られますが、3.8秒かかります。

このクエリを最適化するために、誰かが私を正しい方向に向けることができますか?

4

3 に答える 3

1

問題は「削除済み」列にあるようです。Products テーブルのほとんどすべての項目が "N" でマークされているため、この場合、"deleted" 列のインデックスはほとんど役に立たないと思います。

できることの 1 つは、product_id (および必要に応じて domain_id) を格納する別のテーブル (deleted_domains_products など) を作成することです。次に、エントリが domain_products から削除されるたびに、そのテーブルにエントリが挿入されるようにトリガーを作成します。次に、クエリを実行する小さなセットを取得します。完了したら、次回のためにそのテーブルを切り詰めることができるので、常に非常に迅速に行う必要があります。

于 2013-01-02T03:17:14.710 に答える
0

次のインデックスを作成してから、クエリを再実行してみてください。

  1. domain_products (product_id、domain_id)
  2. 製品 (id、削除済み)

これがどうなるか教えてください

于 2013-01-01T17:44:08.243 に答える
0

これを試して、所要時間を教えてください。

SELECT `products`.*
FROM   `products`
WHERE  `products`.`deleted` = 'N'
AND    NOT EXISTS (SELECT 1 
               FROM `domains_products` 
               WHERE `domains_products`.`product_id` = `products`.`id`
              );
ORDER BY `products`.`id` ASC
于 2013-01-01T18:09:14.833 に答える