2

以前にログに記録された価格の詳細と共にいくつかの製品を取得するクエリの最適化に苦労しています。

私の 3 つのサブクエリは、最後に記録された価格を返すために降順と制限 1 を使用し、ログ テーブルには数万行が含まれているため (長期的には数百万行が含まれる可能性があります)、クエリ結果を生成するための 5 秒の領域 (約 3000 の製品があります)。

SELECT products.*, 
    (SELECT value_new FROM log_actions 
     WHERE action='edit' AND target_entity='net_price_euro' 
     AND target_table='products' 
     AND target_id=products.product_id
     ORDER BY log_time DESC LIMIT 1
    ) AS previous_net_price_euro,
    (SELECT value_new FROM log_actions 
     WHERE action='edit' AND target_entity='retail_sterling' 
     AND target_table='products' AND target_id=products.product_id
     ORDER BY log_time DESC LIMIT 1
     ) AS previous_retail_sterling,
    (SELECT value_new FROM log_actions 
     WHERE action='edit' AND target_entity='gp' 
     AND target_table='products' 
     AND target_id=products.product_id
     ORDER BY log_time DESC LIMIT 1
    ) AS previous_gp
FROM products
WHERE products.deleted IS NULL ORDER BY products.status asc

私が知る限り、関連するすべてのフィールドにインデックスが付けられています。上記で EXPLAIN を実行すると、次の結果が返されます。

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     products    ALL     deleted     NULL    NULL    NULL    3192    Using where
4   DEPENDENT SUBQUERY  log_actions     ref     target_entity,target_id,action,target_table     target_id   4   products.product_id     4   Using where; Using filesort
3   DEPENDENT SUBQUERY  log_actions     ref     target_entity,target_id,action,target_table     target_id   4   products.product_id     4   Using where; Using filesort
2   DEPENDENT SUBQUERY  log_actions     ref     target_entity,target_id,action,target_table     target_id   4   products.product_id     4   Using where; Using filesort

デスクインデックスを追加するとパフォーマンスが向上する可能性があることを読みましたが、さらに読むと、MySQL は現在これをサポートしていないようです。

4

2 に答える 2

2

このクエリは、問題を少し考え直しています。DESC インデックスは mysql ではまだサポートされていないと言っているのは正しいので、あなたよりも少ない回数で注文するクエリを作成しようとしました (3 回注文します)。

SELECT products.*, 
    l1.value_new AS previous_net_price_euro,
    l2.value_new AS previous_retail_sterling,
    l3.value_new AS previous_gp
FROM products
    INNER JOIN (
            SELECT target_id, target_entity, MAX(log_time) AS mx FROM log_actions
            WHERE
                action='edit' 
            AND target_table='products'
            GROUP BY target_id, target_entity
        ) lastvalues ON lastvalues.target_id = products.product_id
    INNER JOIN (
            SELECT target_id, target_entity, log_time, value_new FROM log_actions
            WHERE
                target_entity = 'net_price_euro' 
            AND action='edit' 
            AND target_table='products'
        ) l1 ON l1.target_id            = lastvalues.target_id 
                AND l1.log_time         = lastvalues.mx 
                AND l1.target_entity    = lastvalues.target_entity
    INNER JOIN (
            SELECT target_id, target_entity, log_time, value_new FROM log_actions
            WHERE
                target_entity = 'retail_sterling' 
            AND action = 'edit' 
            AND target_table = 'products'
        ) l2 ON l2.target_id            = lastvalues.target_id 
                AND l2.log_time         = lastvalues.mx 
                AND l2.target_entity    = lastvalues.target_entity
    INNER JOIN (
            SELECT target_id, target_entity, log_time, value_new FROM log_actions
            WHERE
                target_entity = 'gp' 
            AND action = 'edit' 
            AND target_table = 'products'
        ) l3 ON l3.target_id            = lastvalues.target_id 
                AND l3.log_time         = lastvalues.mx 
                AND l3.target_entity    = lastvalues.target_entity
WHERE products.deleted IS NULL 
ORDER BY products.status ASC

この場合、log_time を含む別のインデックスを使用できます。これにより、内部結合が高速化される可能性があります。

于 2013-01-30T15:09:04.663 に答える
1

3 つのインライン サブクエリはすべて類似しています。

(SELECT value_new FROM log_actions 
 WHERE action = 'edit' 
   AND target_entity = 'net_price_euro' 
   AND target_table = 'products' 
   AND target_id = products.product_id
 ORDER BY log_time DESC LIMIT 1
) 

以下にインデックスを追加します。

 (action, target_table, target_entity
 ,target_id, log_time, value_new)

インデックス内の列の順序は、最初の 3 つの列では重要ではありませんが、最後の 3 つの列では重要です。(..., target_id, log_time, value_new)

于 2013-01-30T14:53:58.553 に答える