我正在尝试优化SQL查询以提高其执行速度。我已经发现"日期"列是问题所在。当我运行此查询时,包括数据库中的日期:
SELECT p.*, preis.preis
FROM produkt p INNER JOIN (SELECT * FROM preis WHERE DATE(preis.Datum) = CURDATE()) preis ON p.id = preis.produkt_id
WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
需要28秒才能得到结果。但是,当我将INNER JOIN select的WHERE子句更改为id > 256981
时,我会得到相同的结果,只需要0062秒。
SELECT p.*, preis.preis
FROM produkt p INNER JOIN (SELECT * FROM preis WHERE preis.id > 256981) preis ON p.id = preis.produkt_id
WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
这是一个很大的区别。
我已经读过一些关于INDEX和不同INDEX类型的文章,但我找不到以正确的方式对DATE字段进行INDEX的解决方案。或者有其他方法可以改进这样的查询吗?
SELECT p.*, q.preis
FROM ( SELECT artikel_id FROM produkt WHERE haendler_id = 1 ) AS a
JOIN produkt p USING(artikel_id)
INNER JOIN
( SELECT preis
FROM preis
WHERE Datum >= CURDATE()
AND Datum < CURDATE() + INTERVAL 1 DAY
) AS q ON p.id = q.produkt_id
并具有以下索引:
preis: INDEX(Datum, produkt_id, preis)
preis: INDEX(produkt_id, Datum, preis)
produkt: INDEX(haendler_id, artikel_id)
produkt: INDEX(artikel_id)
如果produkt只能有一个preis
,那么还有另一种选择。
我们确实需要查看SHOW CREATE TABLE
——以检查数据类型、PRIMARY KEY和其他内容。
您是否尝试过在不带日期函数的datum
上直接使用不带子查询和条件的联接,如下所示:
SELECT p.*, preis.preis
FROM produkt p
INNER JOIN preis ON p.id = preis.produkt_id
WHERE preis.Datum >= CURDATE() and preis.Datum < DATE_ADD(CURDATE(), INTERVAL 1 DAY)
AND artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
您可以在preis.Datum
上创建索引,如下所示:
CREATE INDEX preis_indx_01 ON preis(Datum);
注意:如果经常在联接中使用produkt_id
,也可以考虑在其上创建索引。
主要问题是,当您使用mysql时,任何像CURDATE()这样的构建函数都会使查询速度变慢,所以尽可能避免它,所以尽量像这样更新您的查询
// first make today date if your code is php then $today = date('Y-m-d');
then use this in mysql
SELECT p.*, preis.preis
FROM produkt p INNER JOIN (SELECT * FROM preis WHERE DATE(preis.Datum) = '$today')
preis ON p.id = preis.produkt_id
WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
如果您也避免日期,效果会更好
SELECT p.*, preis.preis
FROM produkt p INNER JOIN (SELECT * FROM preis WHERE preis.Datum = '$today')
preis ON p.id = preis.produkt_id
WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
我认为这将帮助你
首先,不要使用子查询。其次,我也不推荐in
。因此:
SELECT p.*, pp.preis
FROM produkt p INNER JOIN
preis pp
ON p.id = pp.produkt_id
WHERE p.Datum >= CURDATE() AND
p.Datum < CURDATE() + INTERVAL 1 DAY AND
EXISTS (SELECT 1
FROM produkt p2
WHERE p2.artikel_id = p.artikel_id AND
p2.haendler_id = 1
);
然后,对于该查询,您需要product(artikel_id, haendler_id)
和preis(Datum, product_id)
上的索引。
我相信您在id
列上有一个索引,但在数据列上没有索引,在该列上定义一个索引应该会得到几乎相同的结果。