多次关联同一张表与CASE过滤,哪种SQL写法性能更优?
两种SQL写法的性能对比与逻辑差异分析
首先得先澄清一个关键问题:你给出的两种写法返回的结果集是不一样的!
第一种写法通过两次左连接,会把table_code='case'和table_code='appe'的行合并到同一行(如果对应keyid存在这两类数据的话),最终返回的行数和MainTable一致。
而第二种写法没有分组,会返回多行:每个匹配的ufd行对应一行,其中只有一个字段有值,另一个为空。如果要让第二种写法和第一种逻辑一致,你需要加上GROUP BY,调整后的写法应该是这样:
SELECT MAX(CASE WHEN ufd.table_code = 'case' THEN ufd.user_field_data_01 ELSE '' END) AS 会员ID, MAX(CASE WHEN ufd.table_code = 'appe' THEN ufd.user_field_data_01 ELSE '' END) AS 申诉ID FROM MainTable (nolock) LEFT JOIN ufd (nolock) ON ufd.keyid = MainTable.keyid GROUP BY MainTable.keyid
接下来我们基于逻辑一致的前提来对比性能和可读性:
性能对比
性能差异主要取决于ufd表的索引情况和数据量:
1. 当ufd表存在合适的索引(推荐场景)
如果ufd表有(keyid, table_code)的复合索引,并且包含user_field_data_01字段(覆盖索引):
- 第一种写法:两次左连接都会直接走索引查找,精准定位到
table_code='case'和table_code='appe'的行,只读取需要的数据,开销极低。 - 第二种写法(带GROUP BY):会先取出该
keyid对应的所有ufd行(包括其他table_code的行,如果有的话),然后进行分组聚合。如果存在大量无关的table_code数据,会读取不必要的行,增加IO和聚合的开销,性能会比第一种差。
2. 当ufd表无合适索引(不推荐场景)
如果没有索引,两种写法都会走表扫描:
- 第一种写法:两次全表扫描,每次过滤对应
table_code,总开销是两次扫描的总和。 - 第二种写法:一次全表扫描,然后分组聚合,开销是一次扫描加上聚合成本。这种情况下第二种可能略优,但实际生产环境中不会允许无索引的大表这么操作,所以这个场景参考意义不大。
3. 数据量小的场景
如果MainTable和ufd的数据量都很小,两种写法的性能差异几乎可以忽略,数据库优化器会快速处理完所有操作。
可读性对比
你提到第一种写法可读性更强,这点完全正确:
- 第一种写法通过别名
UfdCase、UfdAppe清晰区分不同类型的连接,每个连接的过滤条件明确,后续维护时一眼就能看懂每个字段对应的业务含义。 - 第二种写法如果需要扩展更多
table_code类型,会不断增加CASE分支,SQL语句会变得冗长,尤其是当CASE逻辑更复杂时,可读性会急剧下降。
总结
- 优先选择第一种写法:在有合适索引的情况下性能更优,同时可读性和可维护性更好。
- 如果数据量极小,两种写法差异可以忽略;但数据量较大时,第一种的性能优势会很明显。
- 一定要注意两种写法的逻辑差异,避免出现结果不符合预期的情况。
内容的提问来源于stack exchange,提问作者Rich Uchytil
相关产品推荐
相关产品推荐

