需求是这样的,就是有 A 、B 两个表,两个表都有 ID 、FullName 、ShortName 三个字段,以及各有一些其他的字段,现在想要这两个表连接查询,条件是 优先 ID 相等,其次 FullName 相等,最后 ShortName 相等的记录,目前是这么做的:
select A.*,B.* from A left join B
on (A.ID=B.ID and B.ID is not null)
or (A.FullName=B.FullName and B.FullName is not null)
or (A.ShortName=B.ShortName and B.ShortName is not null)
其中 A 表数据比较少,B 表数据有 20 多 w,这样查出来需要 30 几秒。。。个人觉得问题应该是出在这个 or 这里,但是不知道有什么办法,请问各位有什么优化的方法吗?
1
liprais 2021-09-07 09:59:24 +08:00 via iPhone
你要的不就是这三个条件的并集么
|
2
gam2046 2021-09-07 10:09:13 +08:00
首先确保三个字段都有索引,然后尝试 right join,即数据少的表 join 数据多的表,如果还是很慢,贴出来 explain 和机器配置
|
3
BiChengfei 2021-09-07 10:22:57 +08:00
信息太少,暂不知道怎么优化,
-- 第一种 sql 似乎可以简写下,不知道会不会命中索引 ``` select A.*, B.* from A inner join B on A.ID = B.ID or A.FullName = B.FullName or A.ShortName = B.ShortName ``` -- 第二种用 union 拼接,不知道这样去重可以吗,也不知道会不会命中索引 ``` select distinct * from ( select A.*, B.* from A inner join B on A.ID = B.ID union select A.*, B.* from A inner join B on A.FullName = B.FullName union select A.*, B.* from A inner join B on A.ShortName = B.ShortName) temp ``` |
4
BiChengfei 2021-09-07 10:29:29 +08:00
左连接,左边表不能为 null,右边表可能为 null,你 sql 中把右边表为 null 的情况排除,那么就是内连接,所以改为 inner join
因为 mysql 会对你的 sql 进行解析优化,再加上有 is not null,所以以前的语句能不能命中索引不知道,不知道有人能有理有据的科普下吗 |
5
BiChengfei 2021-09-07 10:38:04 +08:00
union 如果可以,这个语句还可以优化,考虑到 id 、fullname 、shortname,这三种匹配数据量的问题,在子语句中进行排除重复数据
|
6
zhangyaxiao072 2021-09-07 10:44:17 +08:00
@BiChengfei 我也想到了第二种,不需要 distinct 了吧,union 会去重
|
7
BiChengfei 2021-09-07 10:46:10 +08:00
@zhangyaxiao072 不知道,很少用这个,楼主试一下就知道了,小问题
|
8
mugglezzz OP |
9
Egfly 2021-09-07 11:25:49 +08:00
要不考虑一下分开查?然后代码里根据业务合并结果集。没必要给数据库太多压力
|