SQL中优化IN的几种方法

 更新时间:2026年08月02日 15:21:21   作者:焚 城  
本文对比了SQL Server中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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SQl 语句(常见)

    SQl 语句(常见)

    SQl 语句(常见)...
    2006-08-08
  • 使用SQL语句创建触发器的实例

    使用SQL语句创建触发器的实例

    触发器 是一种特殊类型的存储过程,它不同于我们前面介绍过的存储过程。存储过程可以通过语句直接调用,而 触发器主要是通过事件进行触发而被执行的,这篇文章主要介绍了使用SQL语句创建触发器的实例,需要的朋友可以参考下
    2023-06-06
  • MMC提示不能打开文件SQLServerEnterpriseManager.MSC的解决方法

    MMC提示不能打开文件SQLServerEnterpriseManager.MSC的解决方法

    MMC不能打开文件SQLServerEnterpriseManager.MSC的解决方法,主要是不能很方便的打开Microsoft SQL 企业管理器
    2010-05-05
  • 浅谈sqlserver的负载均衡问题

    浅谈sqlserver的负载均衡问题

    今天想推荐大家尝试使用第三方的组件和工具,典型的就是一款ICX数据库路由。当然,我和这些工具的厂商也不熟,所以本文显然不是广告
    2013-10-10
  • SQL Server Transact-SQL编程详解

    SQL Server Transact-SQL编程详解

    这篇文章主要为大家介绍了SQL Server Transact-SQL编程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • SQL Server如何通过创建临时表遍历更新数据详解

    SQL Server如何通过创建临时表遍历更新数据详解

    这篇文章主要给大家介绍了关于SQL Server如何通过创建临时表遍历更新数据的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Sql Server 压缩数据库日志文件的方法

    Sql Server 压缩数据库日志文件的方法

    Sql Server 日志 _log.ldf文件太大,数据库文件有500g,日志文件也达到了500g,占用磁盘空间过大,且可能影响程序性能,需要压缩日志文件,下面小编给大家讲解下Sql Server 压缩数据库日志文件的方法,感兴趣的朋友一起看看吧
    2022-11-11
  • MS SQL Server游标(CURSOR)的学习使用

    MS SQL Server游标(CURSOR)的学习使用

    使用MS SQL Server这样久,游标一直没有使用过。以前都是使用WHILE循环加临时表来实现。刚刚联系个示例了解到游标概念与语法
    2014-06-06
  • SQL获取第一条记录的方法(sqlserver、oracle、mysql数据库)

    SQL获取第一条记录的方法(sqlserver、oracle、mysql数据库)

    本文给大家收集整理些关于sql获取第一条记录的方法,包括sqlserver获取第一条记录,oracle获取第一条记录,mysql获取第一条记录,对sql获取第一条记录的方法感兴趣的朋友可以参考下本篇文章
    2015-11-11
  • CentOS8安装SQLServer2019的过程

    CentOS8安装SQLServer2019的过程

    这篇文章主要介绍了CentOS8安装SQLServer2019的步骤,本文通过命令实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04

最新评论