Reputation: 163
I have an SQL query that runs for 114 seconds. The table contains 224000 rows.
Why isn't it using key for 'products' table?
Does anybody have some ideas how to optimize this query?
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|
+--+------------------+---------+----+------------------------+----------+-------+-------+------+-----------+
Upvotes: 0
Views: 118
Reputation: 21184
MySQL is really bad at optimizing subqueries like this, so you have to help it bit, if possible, rewriting it using joins. For the first subquery this should be easy:
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
)
However, this will likely not yet solve the problem with not using keys on the product table, since the second query is more complicated. However, it should be rewritable using 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
The IS NULL
part is needed for products with structure count 0, since they will not match in the join. This query should be much easier for the query processor to use appropriate indexes. If it still won't use them, check you have them on the correct columns.
Upvotes: 1