我试图加快一个SQL查询,这个查询返回了15个最便宜的产品,这些产品具有一些零售商销售的一组特定的特征(宽度,高度,直径和负载)。 de DB中约有300k产品。总价格计算如下:
totalPrice =数量*(价格 - 折扣*价格)+ shippingCost
其中:
我的问题是折扣和 shippingsCost 依赖于太多参数来存储每个总价格组合,以便使查询运行得更快。因此,我认为我坚持使用子查询。
以下是SQL查询的简化版本,其中产品数量设置为2。
SELECT `P`.*, `B`.`name_local` as brandName, `R`.`name` as retailerName, `D`.`amount` as discount, `S`.`shippingCost`, ROUND(P.price * 2 + IFNULL(S.shippingCost, 0) - IFNULL(P.price * D.amount / 100 * 2, 0), 2 ) as totalPrice
FROM (`Product` P)
JOIN `Brand` B ON `B`.`id` = `P`.`idBrand`
JOIN `Retailer` R ON `R`.`id` = `P`.`idRetailer`
LEFT JOIN `Shipping` S ON `S`.`idRetailer` = `P`.`idRetailer` AND S.nbProduct = (SELECT nbProduct FROM `Shipping` WHERE nbProduct <= 2 ORDER BY nbProduct DESC LIMIT 1)
LEFT JOIN `Discount` D ON `D`.`idRetailer` = `P`.`idRetailer` AND D.amount = (SELECT MAX(amount) FROM Discount D WHERE (D.vehicle = P.vehicle OR D.vehicle = 0) AND D.idRetailer = P.idRetailer AND D.start <= 1451825895 AND D.end >=1451825895)
WHERE `width` = '195'
AND `height` = '65'
AND `diameter` = '15'
AND `load` >= 0
ORDER BY `totalPrice` ASC
LIMIT 15
我使用的是mysql 14.14。在我的机器上,查询大约需要150ms才能执行。通过避免使用当前时间戳来进行折扣,可以更好地利用mysql查询缓存。但是,查询需要很长时间才能执行第一次,并且很快从查询缓存中刷新(由于许多组合)。以下是查询explain
命令的结果:
+----+--------------------+----------+--------+-----------------------------------------------+------------+---------+------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+----------+--------+-----------------------------------------------+------------+---------+------------------------+-------+----------------------------------------------+
| 1 | PRIMARY | P | ref | idBrand,idRetailer,width,height,diameter,load | width | 12 | const,const,const | 13268 | Using where; Using temporary; Using filesort |
| 1 | PRIMARY | S | ref | idRetailer | idRetailer | 4 | mydb.P.idRetailer | 1 | Using where |
| 1 | PRIMARY | B | eq_ref | PRIMARY | PRIMARY | 4 | mydb.P.idBrand | 1 | |
| 1 | PRIMARY | R | eq_ref | PRIMARY | PRIMARY | 4 | mydb.P.idRetailer | 1 | |
| 1 | PRIMARY | D | ref | idRetailer | idRetailer | 4 | mydb.S.idRetailer | 1 | |
| 3 | DEPENDENT SUBQUERY | D | ref | idRetailer,start | idRetailer | 4 | mydb.P.idRetailer | 1 | Using where |
| 2 | SUBQUERY | Shipping | ALL | NULL | NULL | NULL | NULL | 48 | Using where; Using filesort |
+----+--------------------+----------+--------+-----------------------------------------------+------------+---------+------------------------+-------+----------------------------------------------+
是否有一种加速这种查询的优雅方法,或者我唯一的方法是改善查询缓存的效果(添加RAM,增加缓存大小等)?
答案 0 :(得分:0)
对于第二个(更复杂的子查询)尝试使用计算折扣LEFT JOIN,让它只执行一次。喜欢这个
...
LEFT JOIN (SELECT MAX(amount) as amount, D.vehicle, D.idRetailer
FROM Discount D
WHERE D.start <= 1451825895
AND D.end >=1451825895
GROUP BY D.idRetailer, D.vehicle) D ON D.`idRetailer` = `P`.`idRetailer`
AND (D.vehicle = P.vehicle OR D.vehicle = 0)