【问题标题】:Why isn't query using index and how to optimize it?为什么不使用索引进行查询以及如何优化它?
【发布时间】:2013-09-06 06:01:14
【问题描述】:

我有一个运行 114 秒的 SQL 查询。该表包含 224000 行。

为什么不使用“产品”表的键?

有人知道如何优化这个查询吗?

EXPLAIN SELECT SUM( quantity * ( 
SELECT IF( netoweight =  '', weight, netoweight ) AS weight
FROM products
WHERE product_nr = it.item ) /1000 ) 
FROM  `inventory_transactions` it
WHERE it.type =  'Production'
AND it.item >  '200000'
AND it.item <  '400000'
AND it.date LIKE  '2013-01%'
AND (
(

SELECT COUNT( id ) 
FROM structure
WHERE final_item = it.item
AND level >  '1'
) <1
)

+--+------------------+---------+----+------------------------+----------+-------+-------+------+-----------+
|id|select_type       |table    |type|possible_keys           |key       |key_len|ref    |rows  |Extra      |
+--+------------------+---------+----+------------------------+----------+-------+-------+------+-----------+
|1 |PRIMARY           |it       |ref |item,type,date          |type      |50     |const  |111604|Using where|
+--+------------------+---------+----+------------------------+----------+-------+-------+------+-----------+
|3 |DEPENDENT SUBQUERY|structure|ref |final_item,level,level_2|final_item|4      |it.item|8     |Using where|
+--+------------------+---------+----+------------------------+----------+-------+-------+------+-----------+
|2 |DEPENDENT SUBQUERY|products |ALL |product_nr              |NULL      |NULL   |NULL   |3831  |Using where|
+--+------------------+---------+----+------------------------+----------+-------+-------+------+-----------+

【问题讨论】:

    标签: mysql sql optimization indexing key


    【解决方案1】:

    MySQL 在优化这样的子查询方面真的很糟糕,所以你必须帮助它一点,如果可能的话,使用连接重写它。对于第一个子查询,这应该很简单:

    SELECT SUM( quantity * weight /1000 ) 
    FROM  `inventory_transactions` it
    JOIN (SELECT product_nr, IF( netoweight =  '', weight, netoweight ) AS weight
         FROM products) AS products
    ON product.product_nr = it.item
    WHERE it.type =  'Production'
    AND it.item >  '200000'
    AND it.item <  '400000'
    AND it.date LIKE  '2013-01%'
    AND (
    (
    
    SELECT COUNT( id ) 
    FROM structure
    WHERE final_item = it.item
    AND level >  '1'
    ) <1
    )
    

    但是,这可能还不能解决不使用产品表上的键的问题,因为第二个查询更复杂。但是,它应该可以使用 group by 重写:

    SELECT SUM( quantity * weight /1000 ) 
    FROM  `inventory_transactions` it
    JOIN (SELECT product_nr, IF( netoweight =  '', weight, netoweight ) AS weight
         FROM products) AS products,
    ON product.product_nr = it.item
    LEFT OUTER JOIN (SELECT final_item, COUNT( id ) AS count
        FROM structure
        WHERE level > '1'
        GROUP BY final_item) AS struct_count
    ON it.item = struct_count.final_item
    WHERE it.type =  'Production'
    AND it.item >  '200000'
    AND it.item <  '400000'
    AND it.date LIKE  '2013-01%'
    AND struct_count.count IS NULL
    

    结构计数为 0 的产品需要 IS NULL 部分,因为它们在连接中不匹配。这个查询应该更容易让查询处理器使用适当的索引。如果它仍然不使用它们,请检查它们是否位于正确的列中。

    【讨论】:

    • 第一次join将执行时间从114s提升到3.5s。非常感谢你。我也会尝试你答案的后半部分,稍后再发布结果。
    • 啊,太好了!很惊讶,虽然这是罪魁祸首。您是否也可以只尝试第二次优化而不进行第一次优化?只是为了得到所有的数字,会很有趣:)
    • 我现在在不同的月份运行查询,结果如下。我原来的查询:197s。您的第一个查询:0.48 秒。没有第一个 JOIN 的第二个查询:花费太多时间并挂起。您使用 JOIN 和 LEFT OUTER JOIN 进行的第二个查询:0.45 秒。相当不错的优化:)。非常感谢@inflagranti!
    猜你喜欢
    • 2016-08-25
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    相关资源
    最近更新 更多