我有一个查询是从上一个同事那里继承的,但是我需要对其进行优化。
此查询返回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;
就像您看到的一样,我的情况并没有太大变化,但仍然得到了更多行。 有人可以告诉我第二个查询未返回完全正确结果的原因。我尝试了许多优化的方法,但是没有成功。 非常感谢!!!
答案 0 :(得分:0)
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)
(按此顺序)SHOW CREATE TABLE
。答案 1 :(得分:0)
new_installed_devices
中的FROM子句中的第一个子查询。在旧版本中,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