如何将多UNION的MySQL查询优化为单查询?
问题描述
这是我在Stack Overflow的第一个问题,请多多包涵。
数据表
| 医生姓名(namadokter) | 门店名称(namaoutlet) | 交易单号(notransaksi) | 处方日期(tanggalresep) | 总账单金额(totaltagihan) |
|---|---|---|---|---|
| richard chandra sp | kfa | kfa132 | 2023-06-01 | 1200 |
| richard chandra sp | kfa | kfa132 | 2023-06-01 | 1300 |
| richard chandra spb | kfb | kfb133 | 2023-06-01 | 700 |
| richard chandra spb | kfb | kfb133 | 2023-06-01 | 800 |
| agus hidayat sp | kfa | kfa100 | 2023-06-01 | 1000 |
| agus hidayat sp | kfa | kfa100 | 2023-06-01 | 2000 |
| agus hidayat spb | kfb | kfb111 | 2023-06-01 | 3000 |
| agus hidayat spb | kfb | kfb111 | 2023-06-01 | 2000 |
当前查询语句
SELECT *, ROW_NUMBER() OVER(ORDER BY namadokter) row_num FROM ( (SELECT namadokter,namaoutlet, COUNT(notransaksi) AS jenis_obat,sum(totaltagihan) FROM laporandokterunitsurabaya where namadokter like '%richard chandra%' and (tanggalresep BETWEEN (SELECT tstart FROM tanggal WHERE id=1) AND (SELECT tend FROM tanggal WHERE id=1)) group by namaoutlet order by namadokter) union (SELECT namadokter,namaoutlet, COUNT(notransaksi) AS jenis_obat,sum(totaltagihan) FROM laporandokterunitsurabaya where namadokter like '%agus hidayat%' and (tanggalresep BETWEEN (SELECT tstart FROM tanggal WHERE id=1) AND (SELECT tend FROM tanggal WHERE id=1)) group by namaoutlet order by namadokter) )a order by namadokter
当前查询结果
| 行号(row_num) | 医生姓名(namadokter) | 门店名称(namaoutlet) | 药品种类数(jenis_obat) | 总账单金额合计(sum(totaltagihan)) |
|---|---|---|---|---|
| 1 | richard chandra sp | kfa | 2 | 2500 |
| 2 | richard chandra spb | kfb | 2 | 1500 |
| 3 | agus hidayat sp | kfa | 2 | 3000 |
| 4 | agus hidayat sp | kfb | 2 | 5000 |
当前查询可正常运行,但当需要UNION 30个及以上SELECT语句时,查询耗时显著增加。我推测原因是每个带通配符的SELECT都会单独执行一次查询,请问是否可以将其改写为单条SELECT语句以优化性能?
优化方案
可以把多个UNION的查询合并成单条语句,核心是用OR组合多个LIKE条件,同时修正分组逻辑确保结果与原查询一致。
优化后的SQL语句
SELECT namadokter, namaoutlet, COUNT(notransaksi) AS jenis_obat, SUM(totaltagihan) AS sum_totaltagihan, ROW_NUMBER() OVER(ORDER BY namadokter) row_num FROM laporandokterunitsurabaya WHERE (namadokter LIKE '%richard chandra%' OR namadokter LIKE '%agus hidayat%') AND tanggalresep BETWEEN (SELECT tstart FROM tanggal WHERE id=1) AND (SELECT tend FROM tanggal WHERE id=1) GROUP BY namadokter, namaoutlet ORDER BY namadokter
关键优化点
- 合并查询条件:用
OR替代多段独立查询的UNION,让数据库仅扫描一次表,避免重复扫描带来的性能损耗。 - 修正分组逻辑:原查询中仅
GROUP BY namaoutlet却选择namadokter,在严格SQL模式下会报错,优化后改为GROUP BY namadokter, namaoutlet,确保逻辑合规且结果准确。 - 简化查询层级:去掉嵌套子查询与
UNION结构,直接在主查询中计算行号,降低查询复杂度。
如果有30个医生姓名需要匹配,只需在OR后继续追加namadokter LIKE '%xxx%'条件即可,无需新增独立查询。
内容的提问来源于stack exchange,提问作者adamenun
相关产品推荐
相关产品推荐

