You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

两张约1600万条记录的表LEFT JOIN查询过慢求助

解决思路

核心问题分析

LEFT JOIN 引入后,由于patients和receivable_transactions是一对多关系,关联后数据行数大幅膨胀,聚合阶段需要处理的数据集远大于原查询,这是性能暴跌的主因。同时当前查询逻辑存在错误:原查询的count(*)统计的是patients表的行数,而LEFT JOIN后count(*)统计的是关联后的总行数(包含receivable_transactions的重复行),会导致计算出的'Sent Back'比例失真。


1. 修正逻辑并避免数据膨胀

如果添加LEFT JOIN是为了后续引入receivable_transactions的统计字段,先对receivable_transactions按关联字段预聚合,再和patients关联,彻底解决一对多导致的行数暴增问题:

-- 预聚合receivable_transactions的统计数据(按需调整统计字段)
WITH rec_agg AS (
    SELECT 
        patient_seq,
        COUNT(*) AS total_transactions -- 示例统计项
    FROM receivable_transactions
    GROUP BY patient_seq
)
SELECT
    p.radiologist, 
    CONCAT((SUM(p.qa_report_sendback)/COUNT(*))*100, '%') AS 'Sent Back'
    -- 可添加receivable的统计字段,比如 SUM(rec_agg.total_transactions) AS total_records
FROM patients AS p
INNER JOIN radiologist AS rad ON p.radiologist = rad.lastname
LEFT JOIN rec_agg ON p.seq = rec_agg.patient_seq
WHERE rad.company = 1
GROUP BY p.radiologist;

如果暂时不需要receivable_transactions的字段,直接移除该LEFT JOIN即可恢复原查询性能。

2. 优化索引策略

针对radiologist表

添加联合索引(company, lastname),让数据库快速过滤出company=1的放射科医生,再关联patients表,缩小patients的扫描范围:

CREATE INDEX idx_rad_company_lastname ON radiologist(company, lastname);

针对patients表

创建覆盖索引(radiologist, qa_report_sendback),让数据库直接从索引中获取聚合所需字段,无需回表查询:

CREATE INDEX idx_pat_rad_sendback ON patients(radiologist, qa_report_sendback);

3. 调整查询执行顺序

先筛选出符合条件的放射科医生列表,再查询patients表,避免全表扫描patients:

SELECT
    p.radiologist, 
    CONCAT((SUM(p.qa_report_sendback)/COUNT(*))*100, '%') AS 'Sent Back'
FROM patients AS p
WHERE p.radiologist IN (
    SELECT lastname FROM radiologist WHERE company = 1
)
-- 如需关联receivable,替换为预聚合后的表
LEFT JOIN rec_agg ON p.seq = rec_agg.patient_seq
GROUP BY p.radiologist;

4. 验证数据膨胀程度

执行以下语句查看关联后的总行数,确认膨胀规模:

SELECT COUNT(*) 
FROM patients AS p
INNER JOIN radiologist AS rad ON p.radiologist = rad.lastname
LEFT JOIN receivable_transactions AS rec ON p.seq = rec.patient_seq
WHERE rad.company = 1;

对比原查询数据集大小:

SELECT COUNT(*) 
FROM patients AS p
INNER JOIN radiologist AS rad ON p.radiologist = rad.lastname
WHERE rad.company = 1;

如果前者是后者的数倍甚至数十倍,说明数据膨胀是性能问题的核心,预聚合receivable_transactions是最优解决方案。


内容的提问来源于stack exchange,提问作者J.T.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 10:13:11