SQL中优化IN的几种方法
一、前言
最近对一个存储过程进行优化,这里记录一下IN在SQLServer中的一些优化和情况。
二、能代替IN的几种方法效率对比

所以 UNION ALL其实是效率最好的,也就是 =ANY()
三、实际写法
3.1 IN
Select * from TableA where name IN ('A','B','C');
3.2 OR
Select * from TableA where name='A' OR name='B' OR name='C';
3.3 EXISTS
SELECT *
FROM TableA a
WHERE EXISTS (
SELECT 1
FROM ( VALUES ('A'),('B'),('C')) AS tmp(name)
3.4 JOIN
-- SQL Server/PostgreSQL/MySQL 8.0+ 语法
SELECT TableA.*
FROM TableA
JOIN ( VALUES ('A'),('B'),('C')) AS tmp(name)
ON TableA.name = tmp.name
3.4 UNION ALL
Select * from TableA where name='A' union all
Select * from TableA where name='B' union all
Select * from TableA where name='C '
或
Select * from TableA where name = ANY('A','B','C');
三、存储过程实例
实现
SELECT * from TableA WHERE
A.name IN ('A','B','C')
AND A.types IN ('1','3','7','8')
AND A.age IN ('33','35','39')
存储过程
declare
@name varchar(100)='A,B,C',
@type varchar(100)='1,3,7,8',
@age varchar(100)='33,35,39'
--列转行
if object_id('tempdb..#MyTemp') is not null
Begin
DROP TABLE #MyTemp
End
Select * Into #MyTempTable1 From
(
SELECT B.id,B.typeid
FROM (
SELECT [value] = CONVERT(XML, '<v>' + REPLACE(@name,',', '</v><v>') + '</v>')
) A
OUTER APPLY(
SELECT id = N.v.value('.', 'nvarchar(100)'),typeid=1
FROM A.[value].nodes('/v') N(v)
) B
Union
SELECT D.id,D.typeid
FROM (
SELECT [value] = CONVERT(XML, '<v>' + REPLACE(@type,',', '</v><v>') + '</v>')
) C
OUTER APPLY(
SELECT id = N.v.value('.', 'nvarchar(100)'),typeid=2
FROM C.[value].nodes('/v') N(v)
) D
Union
SELECT D.id,D.typeid
FROM (
SELECT [value] = CONVERT(XML, '<v>' + REPLACE(@age,',', '</v><v>') + '</v>')
) E
OUTER APPLY(
SELECT id = N.v.value('.', 'nvarchar(100)'),typeid=3
FROM C.[value].nodes('/v') N(v)
)F
) as T
--EXISTS 子查询
Select * from TableA A where
A.name IN (select id from #MyTemp where typeid=1)
AND A.types IN (select id from #MyTemp where typeid=2)
AND A.age IN (select id from #MyTemp where typeid=3)
四、实际情况
情况1
有一个很奇怪的情况,当@name='A’时,存储过程中
Select * from TableA A where A.name IN (select id from #MyTemp where typeid=1) AND A.types IN (select id from #MyTemp where typeid=2) AND A.age IN (select id from #MyTemp where typeid=3)
A.name... 比 A.name='A' 或 A.name in ('A') 查询时间多了一倍。 types、age 确没影响
改成Join后,得到解决:
Select * from TableA A JOIN #MyTempTable1 B ON B.id = A.DATAAREAID AND B.typeid=1 WHERE A.types IN (select id from #MyTemp where typeid=2) AND A.age IN (select id from #MyTemp where typeid=3)
情况2
在in 不走索引的情况下,union all 效率最高
再改进:
Select * from TableA A JOIN #MyTempTable1 B ON B.id = A.DATAAREAID AND B.typeid=1 WHERE A.types = ANY(select id from #MyTemp where typeid=2) AND A.age = ANY(select id from #MyTemp where typeid=3)
五. 结论
如果有索引, 几种方式效率差不多。没有索引都避免不了全表查询。
IN 列表包含大量值(如上千个)时,或者优化器以为IN会包含大量值,
可能生成低效的执行计划。
改成Join 效果可能有质的飞跃。
如: A.name IN (select id from #MyTemp where typeid=1)
计划会以为 IN 里的值会很多,给出很糟糕的执行计划。
效率无绝对,由「数据量、索引、执行计划」决定,常规业务场景下的高效层级为:UNION ALL ≈ JOIN(等值连接) > EXISTS > IN > OR
但考虑到 union all 不去重的特性, join+临时表的用法应该是最值得推荐的。
到此这篇关于SQL中优化IN的几种方法的文章就介绍到这了,更多相关SQL 优化IN内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
MMC提示不能打开文件SQLServerEnterpriseManager.MSC的解决方法
MMC不能打开文件SQLServerEnterpriseManager.MSC的解决方法,主要是不能很方便的打开Microsoft SQL 企业管理器2010-05-05
SQL获取第一条记录的方法(sqlserver、oracle、mysql数据库)
本文给大家收集整理些关于sql获取第一条记录的方法,包括sqlserver获取第一条记录,oracle获取第一条记录,mysql获取第一条记录,对sql获取第一条记录的方法感兴趣的朋友可以参考下本篇文章2015-11-11


最新评论