我有当前的查询:
select m.id, ms.severity, ms.risk_score, count(distinct si.id), boarding_date_tbl.boarding_date
from merchant m
join merchant_has_scan ms on m.last_scan_completed_id = ms.id
join scan_item si on si.merchant_has_scan_id = ms.id and si.is_registered = true
join (select m.id merchant_id, min(s_for_boarding.scan_date) boarding_date
from merchant m
left join merchant_has_scan ms on m.id = ms.merchant_id
left join scan s_for_boarding on s_for_boarding.id = ms.scan_id and s_for_boarding.scan_type = 1
group by m.id) boarding_date_tbl on boarding_date_tbl.merchant_id = m.id
group by m.id
limit 100;
当我在大计划(约2mil"商家")上运行时,它需要超过20秒。 但如果我把它分成:
select m.legal_name, m.unique_id, m.merchant_status, s_for_boarding.scan_date
from merchant m
join merchant_has_scan ms on m.id = ms.merchant_id
join scan s_for_boarding on s_for_boarding.id = ms.scan_id and s_for_boarding.scan_type = 1
group by m.id
limit 100;
和
select m.id, ms.severity, ms.risk_score, count(distinct si.id)
from merchant m
join merchant_has_scan ms on m.last_scan_completed_id = ms.id
join scan_item si on si.merchant_has_scan_id = ms.id and si.is_registered = true
group by m.id
limit 100;
两者都需要大约0.1秒 原因很明显,下限意味着它不需要做很多事情来获得前100个。很明显内部选择导致第一个查询运行的次数与它一样多。 我的问题是,有一种方法可以仅在相关商家上进行内部选择,而不是在整个桌子上进行内部选择吗?
在内部查询之前制作left join
而不是join
有助于将其缩短为6秒,但如果我进行2次查询,它仍会比我获得的要多得多
为商家创建表格:
CREATE TABLE `merchant` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`last_scan_completed_id` bigint(20) DEFAULT NULL,
`last_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `FK_9lhkm7tb4bt87qy4j3fjayec5` FOREIGN KEY (`last_scan_completed_id`) REFERENCES `merchant_has_scan` (`id`)
)
merchant_has_scan:
CREATE TABLE `merchant_has_scan` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`merchant_id` bigint(20) NOT NULL,
`risk_score` int(11) DEFAULT NULL,
`scan_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_merchant_id` (`scan_id`,`merchant_id`),
CONSTRAINT `FK_3d8f81ts5wj2u99ddhinfc1jp` FOREIGN KEY (`scan_id`) REFERENCES `scan` (`id`),
CONSTRAINT `FK_e7fhioqt9b9rp9uhvcjnk31qe` FOREIGN KEY (`merchant_id`) REFERENCES `merchant` (`id`)
)
scan_item:
CREATE TABLE `scan_item` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`is_registered` bit(1) NOT NULL,
`merchant_has_scan_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_avcc5q3hkehgreivwhoc5h7rb` FOREIGN KEY (`merchant_has_scan_id`) REFERENCES `merchant_has_scan` (`id`)
)
扫描:
CREATE TABLE `scan` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`scan_date` datetime DEFAULT NULL,
`scan_type` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
和解释:
答案 0 :(得分:0)
EXPLAIN
中的第一个表,因为它必须是。merchant_has_scan
是一个很多:很多表,但没有优化提示here - 修复这可能是加速它的最大因素。警告:提示建议删除id
,但您似乎可以使用id
,所以请保留它。COUNT(DISTINCT si.id)
和JOIN si...
可以替换为( SELECT COUNT(*) FROM scan_item WHERE ...)
,从而消除其中一个JOINs
并可能会减少Explode-Implode。LEFT JOIN
- 您有时希望NULL
获得boarding_date
吗?如果没有,请使用JOIN
,而不是LEFT JOIN
。 (最好说出你的意图,而不是让查询保持多种解释。)LEFTs
,那么由于m.id
和merchant_id
被指定为相同,为什么要在SELECT
中列出它们? (这是一个混乱的因素,而不是速度问题)。LIMIT 100
添加到内部查询中。如果需要,也可以将它添加到派生表中。然后,可以从外部查询中删除GROUP BY m.id LIMIT 100
。