[英]My SQL - trying to optimize Query returns more rows
我有一个从我以前的同事那里继承的查询,但我需要对其进行优化。
此查询返回 72 行。
SELECT id, contract_no, customer, address, cm_mac, aps
FROM
(
SELECT *
from new_installed_devices
where insert4date >='2018-10-28'
AND insert4date <='2018-10-28'
AND install_mark<2
) as d1
left join
(
SELECT *
from
(
SELECT contract_no AS c_no, cm_mac AS c_mc, MIN(tstamp) as time2,
sum(1) as aps
from devices_change
where contract_no in (
SELECT distinct(contract_no)
from devices_change
where tstamp >= '2018-10-28 06:59:59'
AND tstamp <= '2018-10-29 07:00:00'
)
group by contract_no, cm_mac
) as mtmbl
where mtmbl.time2 >= '2018-10-28 06:59:59'
and mtmbl.time2 <= '2018-10-29 07:00:00'
) as tmp ON d1.contract_no=tmp.c_no
where aps>0
group by contract_no, customer, address, cm_mac;
执行需要 20 秒。 我重写它,试图优化它,但在这种情况下,我有 75 行(返回 3 行额外的行),但结果在 2 秒内显示。
我已经这样做了(唯一的区别是在一个子查询中):
SELECT id, contract_no, customer, address, cm_mac, aps
FROM
(
SELECT *
from new_installed_devices
where insert4date >='2018-10-28'
AND insert4date <='2018-10-28'
AND install_mark<2
) as d1
left join
(
SELECT *
from
(
SELECT distinct
(contract_no) AS c_no,
cm_mac AS c_mc, MIN(tstamp) as time2,
sum(1) as aps
from devices_change
where tstamp >= '2018-10-28 06:59:59'
AND tstamp <= '2018-10-29 07:00:00'
group by contract_no, cm_mac
) as mtmbl
where mtmbl.time2 >= '2018-10-28 06:59:59'
and mtmbl.time2 <= '2018-10-29 07:00:00'
) as tmp ON d1.contract_no=tmp.c_no
where aps>0
group by contract_no, customer, address, cm_mac;
就像您看到的那样,在我的情况下,我并没有太大变化,但我仍然得到了更多的行,它应该是结果。 有人可以告诉我为什么我的第二个查询没有返回完全正确的结果。 我尝试了很多东西来优化但没有成功。 非常感谢!!!
SELECT *
。 看起来contract_no
是dl
唯一需要的列,因此来自new_installed_devices
。insert4date
的相等性吗?INDEX(insert4date, install_mark, dl)
(按顺序)IN ( SELECT ... )
。 通常最好使用EXISTS
或LEFT JOIN
。DISTINCT(contract_no), ...
-- DISTINCT
不是函数; 它的效果适用于整个表达式集。 摆脱DISTINCT
因为GROUP BY
有这种效果。INDEX(contract_no, cm_max, tstamp)
( INDEX(contract_no, cm_max, tstamp)
顺序)SHOW CREATE TABLE
。new_installed_devices
的直接引用,以及 WHERE 子句中的某些条件。 在旧版本中,MySQL 不能很好地处理子查询,所以尽量避免在 FROM 子句中使用它们(特别是如果你有超过 1 或 2 个)。mtmbl.time2
的范围条件可以折叠到子查询的 HAVING 子句中,以确保您尽快过滤该数据,而无需使用该子查询创建大型临时表。在猜测 MySQL 会在此处选择的顺序时,您可以尝试添加这些索引并运行以下查询,看看是否效果更好。 我将上面的建议应用于下面的查询(希望我对列来源的猜测是正确的,否则请相应地修复所有内容):
ALTER TABLE `devices_change` ADD INDEX `devices_change_idx_no_mac_tstamp` (`contract_no`,`cm_mac`,`tstamp`);
ALTER TABLE `devices_change` ADD INDEX `devices_change_idx_tstamp_no` (`tstamp`,`contract_no`);
ALTER TABLE `new_installed_devices` ADD INDEX `new_installed_device_idx_no_insert4date` (`contract_no`,`insert4date`);
查询:
SELECT
new_installed_devices.id,
new_installed_devices.contract_no,
new_installed_devices.customer,
new_installed_devices.address,
new_installed_devices.cm_mac,
new_installed_devices.aps
FROM
new_installed_devices AS d1
LEFT JOIN
(
SELECT
*
FROM
(SELECT
devices_change.contract_no AS c_no,
devices_change.cm_mac AS c_mc,
MIN(devices_change.tstamp) AS time2,
sum(1) AS aps
FROM
devices_change
WHERE
devices_change.contract_no IN (
SELECT
DISTINCT (devices_change.contract_no)
FROM
devices_change
WHERE
devices_change.tstamp >= '2018-10-28 06:59:59'
AND devices_change.tstamp <= '2018-10-29 07:00:00'
)
GROUP BY
devices_change.contract_no,
devices_change.cm_mac
HAVING
devices_change.time2 >= '2018-10-28 06:59:59'
AND devices_change.time2 <= '2018-10-29 07:00:00'
ORDER BY
NULL) AS mtmbl) AS tmp
ON d1.contract_no = tmp.c_no
WHERE
aps > 0
AND d1.insert4date >= '2018-10-28'
AND d1.insert4date <= '2018-10-28'
AND d1.install_mark < 2
GROUP BY
new_installed_devices.contract_no,
new_installed_devices.customer,
new_installed_devices.address,
new_installed_devices.cm_mac
ORDER BY
NULL
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.