1

次のクエリがあります。

SELECT `p_products`.`id`, `p_products`.`name`, `p_products`.`date`, 
       `p_products`.`img`, `p_products`.`safe_name`, `p_products`.`sku`, 
       `p_products`.`productstatusid`, `op`.`quantity`
FROM `p_products` 
INNER JOIN `p_product_p_category` 
        ON `p_products`.`id` = `p_product_p_category`.`p_product_id`
LEFT JOIN (SELECT `p_product_id`,`order_date`,SUM(`product_quantity`) as quantity 
           FROM `p_orderedproducts` 
           WHERE `order_date`>='2013-03-01 16:51:17' 
           GROUP BY `p_product_id`) AS op
       ON `p_products`.`id` = `op`.`p_product_id`
WHERE `p_product_p_category`.`p_category_id` IN ('15','23','32') 
  AND `p_products`.`active` = '1'
GROUP BY `p_products`.`id`
ORDER BY `date` DESC

説明は次のように述べています。

id select_type テーブル タイプ possible_keys キー key_len ref 行 エクストラ
1 PRIMARY p_product_p_category ref p_product_id,p_category_id,p_product_id_2 p_category_id 4 const 8239 一時的な使用; ファイルソートの使用
1 PRIMARY p_products eq_ref PRIMARY PRIMARY 4 pdev.p_product_p_category.p_product_id 1 where の使用
1 プライマリ すべて NULL NULL NULL NULL 78  
2 DERIVED p_orderedproducts index order_date p_product_id 4 NULL 201 where の使用

また、p_products.date を含む多数の列にインデックスを作成しています。

問題は、多数のカテゴリに 5000 を超える製品がある場合の速度です。60000 個の製品に 1 秒以上かかります。物事をスピードアップする方法はありますか?

これは、左結合を削除した場合にも当てはまります。その場合、結果は次のようになります。

id select_type テーブル タイプ possible_keys キー key_len ref 行 エクストラ
1 SIMPLE p_product_p_category インデックス p_product_id,p_category_id,p_product_id_2 p_product_id_2 8 NULL 91167 where; を使用。インデックスの使用; 一時的な使用; ファイルソートの使用
1 SIMPLE p_products eq_ref PRIMARY PRIMARY 4 pdev.p_product_p_category.p_product_id 1 where の使用

中間テーブル p_product_p_category には、p_product_id と p_category_id の両方のインデックスと、両方を組み合わせたインデックスがあります。

オチの提案を試してみると、次のようになりました。

id select_type テーブル タイプ possible_keys キー key_len ref 行 エクストラ
1 PRIMARY ALL NULL NULL NULL NULL 62087 一時的な使用。ファイルソートの使用
1 PRIMARY nr1media_products eq_ref PRIMARY PRIMARY 4 cats.nr1media_product_id 1 where の使用
2 派生 nr1media_product_nr1media_category 範囲 nr1media_category_id nr1media_category_id 4 NULL 62066 where の使用

カテゴリの中間テーブルで製品を結合して、選択したカテゴリのすべての固有の製品を日付でソートして取得するにはどうすればよいかという質問を単純化できると思います。

編集:

これにより、順序付けやグループ化に一時テーブルを使用せずに、カテゴリ内のすべての一意の製品が得られます。

SELECT
    `p_products`.`id`,
    `p_products`.`name`,
    `p_products`.`img`,
    `p_products`.`safe_name`,
    `p_products`.`sku`,
    `p_products`.`productstatusid`
FROM
    p_products
WHERE
    EXISTS (
        SELECT
            1
        FROM
            p_product_p_category
        WHERE
            p_product_p_category.p_product_id = p_products.id
        AND p_category_id IN ('15', '23', '32')
    )
AND p_products.active = 1
ORDER BY
    `date` DESC

上記のクエリは非常に高速で、group by order by (0.04 VS 0.7 秒) を使用した結合よりもはるかに高速ですが、一時テーブルなしでこのクエリを実行できる理由はわかりません。

私は、orderedproducts 結合の別の解決策を見つける必要があると思いますが、それでもクエリが 1 秒以上遅くなります。cron を作成して、販売された製品のランキングを毎晩 1 回更新し、その情報を p_products テーブルに保存します。

誰かが決定的な解決策を持っていない限り...

4

2 に答える 2

2

すべてのタイプのカテゴリを製品に結合しています - その場合にのみ、カテゴリ ID でフィルタリングされます

の代わりに、できるだけ早くクエリを制限するようにしてください。

INNER JOIN `p_product_p_category`

行う

INNER JOIN ( SELECT * FROM `p_product_p_category` WHERE `p_category_id` IN ('15','23','32') )

最初から製品の小さなサブセットに取り組むことができるように

于 2013-05-30T15:23:15.730 に答える
2

考えられる解決策の 1 つは、派生テーブルを削除して、Group By を 1 つだけ実行することです。

Select P.id, P.name, P.date
    , P.img, P.safe_name, P.sku
    , P.productstatusid
    , Sum( OP.product_quantity ) As quantity
From p_products As P
    Join p_product_p_category As CAT
        On p_products.id = CAT.p_product_id

    Left Join p_orderedproducts As OP
        On OP.p_product_id = P.id
            And OP.order_date >= '2013-03-01 16:51:17' 

Where CAT.p_category_id In ('15','23','32') 
    And P.active = '1'
Group By P.id, P.name, P.date
    , P.img, P.safe_name, P.sku
    , P.productstatusid
Order By P.date Desc
于 2013-05-30T15:25:54.407 に答える