it编程 > 数据库 > MsSqlserver

SQL中优化IN的几种方法

6人参与 2026-08-03 MsSqlserver

一、前言

最近对一个存储过程进行优化,这里记录一下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内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

您想发表意见!!点此发布评论

推荐阅读

SQL PARTITION BY用法小结

08-03

SQL Server DML 操作的项目实战

08-03

SQL image转汉字乱码处理的问题解决

08-03

你以为迁移完事了?其实这些 SQL 逻辑陷阱正悄悄等着你呢(七大逻辑陷阱及修复方案)

08-02

Android利用SQLite实现简单的记事本(附源码)

07-31

SQL Server表被锁了怎么办?快速查看和解锁的实用方法

07-29

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论