我有以下查询:
SELECT driver_id, first_name, last_name
FROM drivers
WHERE driver_id NOT IN
(SELECT DISTINCT w.driver_id from waybills w
JOIN drivers d ON d.driver_id = w.driver_id
WHERE w.waybill_owner = 1
AND w.waybill_status = 'dispatched'
AND w.delivery_date = '2014-10-28')
AND driver_id NOT IN
(SELECT DISTINCT wm.driver_id from waybill_movements wm
JOIN drivers d ON d.driver_id = wm.driver_id
WHERE wm.movement_owner = 1
AND wm.delivery_date = '2014-10-28')
AND status = 'active'
AND driver_owner = 1
ORDER BY last_name ASC
如何优化此查询?
查询运行良好并返回预期结果,但我的问题是是否可以优化查询。
非常感谢您的时间和帮助。
更新
而且,是的,我有这些索引:
运单(waybill_owner,waybill_status,w.delivery_date) waybill_movements(wm.movement_owner,delivery_date) drivers(driver_id主键和驱动程序(status,driver_owner)
表格结构不需要它进行优化
我没想到会有这么多答案。谢谢大家。
答案 0 :(得分:2)
这取决于is
的定义。您可能希望将这些WHERE IN
子查询重写到您的FROM
子句中,然后针对该子查询重新运行现有查询,并查看MySQL解释是否为其提供了不同的执行路径和统计信息。
毫无疑问,由于您几乎必须在现有查询中三次点击drivers
表格才能获得所需的结果。这完全是不必要的开销。
SELECT d.driver_id, d.first_name, d.last_name
FROM drivers d
LEFT OUTER JOIN waybills w ON
d.driver_id = w.driver_id AND
w.waybill_owner = 1 AND
w.waybill_status = 'dispatched' AND
w.delivery_date = '2014-10-28'
LEFT OUTER JOIN waybill_movements wm ON
d.driver_id = wm.driver_id AND
wm.movement_owner = 1 AND
wm.delivery_date = '2014-10-28')
WHERE
w.driver_id IS NULL AND
wm.driver_id IS NULL AND
d.status = 'active' AND
d.driver_owner = 1
ORDER BY last_name ASC
你的ORDER BY
也很昂贵。如果不需要,那么删除它可能是个好主意。
您可能想要运行@StuartLC建议的SQL,并通过解释和看到MySQL比其中一个更好。你可能会发现他有更好的结果,但有时它是硬币翻转。对于派生表,MySQL通常不是非常快速,因此尽可能多地填充传统连接可以产生更好的结果。但这完全取决于表格的大小,是否有适当的索引和所有有趣的东西。
答案 1 :(得分:1)
假设您已经查看了索引
waybills(waybill_owner, waybill_status, w.delivery_date)
waybill_movements (wm.movement_owner, delivery_date)
drivers(driver_id)
- 可能是主键?还可能drivers(status, driver_owner)
其他两项改进让人想起
where driver_id IS NOT NULL
如果这是可以为空的外键NOT IN
SELECT driver_id, first_name, last_name
FROM drivers
WHERE driver_id NOT IN
(
SELECT DISTINCT w.driver_id
from waybills w
WHERE w.waybill_owner = 1
AND w.waybill_status = 'dispatched'
AND w.delivery_date = '2014-10-28'
UNION
SELECT DISTINCT wm.driver_id
from waybill_movements wm
WHERE wm.movement_owner = 1
AND wm.delivery_date = '2014-10-28'
)
AND status = 'active'
AND driver_owner = 1
ORDER BY last_name ASC
答案 2 :(得分:1)
我通常发现执行left-joins并查找表结果为NULL更容易,并且可以很好地利用索引。
The drivers table I would have an index ON (driver_owner, status, driver_id)
Your waybill table, index ON(waybill_owner, driver_id, delivery_date, waybill_status)
waybill_movements, index ON(movement_owner, driver_id, delivery_date )
SELECT
d1.driver_id,
d1.first_name,
d1.last_name
FROM
drivers d1
LEFT JOIN waybills w
ON d1.driver_id = w.driver_id
AND d1.driver_owner = w.waybill_owner
AND w.waybill_status = 'dispatched'
AND w.delivery_date = '2014-10-28'
LEFT JOIN waybill_movements wm
ON d1.driver_id = wm.driver_id
AND d1.driver_owner = wm.movement_owner
AND wm.delivery_date = '2014-10-28'
where
d1.driver_owner = 1
AND d1.status = 'active'
AND w.driver_ID IS NULL
AND wm.driver_id IS NULL
ORDER BY
d1.last_name ASC
通过为运单和waybill_movements添加“IS NULL”,您只能获得那些没有匹配记录的那些。
另外,看到你的waybill_owner = 1 ......与driver_owner = 1的巧合也是一致的吗?如果运单所有者应始终与驱动程序所有者相同,那么我会将运单表上的索引更改为首先使用waybill_owner,然后更改driver_id,然后将其余部分更改为基于drivers.driver_owner =运单的连接。 waybill_owner(类似于waybill_movements)
根据反馈修改
根据相同的drivers.driver_owner表修改索引和要加入的查询到运单表,以防止可能存在任何奇怪的可能性导致跨所有者匹配的错误结果。
答案 3 :(得分:0)
SELECT d.driver_id, d.first_name, d.last_name
FROM drivers AS d
LEFT JOIN waybills AS w
ON d.driver_id = w.driver_id
AND w.waybill_owner = 1
AND w.waybill_status = 'dispatched'
AND w.delivery_date = '2014-10-28'
LEFT JOIN waybill_movements AS wm
ON d.driver_id = wm.driver_id
AND wm.movement_owner = 1
AND wm.delivery_date = '2014-10-28'
WHERE w.driver_id IS NULL
AND wm.driver_id IS NULL
AND d.status = 'active'
AND d.driver_owner = 1
ORDER BY d.last_name ASC