我们知道,在sql中使用IN让我们的where子句可以规定多个值。当需要从一个集合中查询包含某几个值的记录的时候,通常我们会选择使用IN来实现,其实,使用JOIN也可以实现这样的功能,而且性能要比IN好。我会从以下几个方面来进行总结。
- 使用IN和JOIN的性能对比
- EF中如何使用JOIN来代替IN
使用IN和JOIN的性能对比
首先来看一段sql语句,然后通过执行计划来比较它们之间的性能。
使用IN和JOIN查询的代码:
下面是它们的执行计划:
通过执行计划,可以看到使用JOIN的性能要比IN好。
EF中如何使用JOIN来代替IN
我们在使用EF的时候, 会有很多像下面这样的查询。
1 List<int> productIds = new List<int> 2 { 3 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 4 }; 5 using (var db = new PackageFHContext()) 6 { 7 var containerResult = db.ProductMasterSet.Where(p => productIds.Contains(p.ProductID)); 8 }
实际上,这种写法生成的sql代码就是使用了IN,下面是使用Sql Server Profiler监测到的结果。
SELECT ….. FROM [dbo].[Pkg_ProductMaster] AS [Extent1] WHERE [Extent1].[ProductID] IN (15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30);
那么,我们怎样来实现JOIN来代替IN呢,我们可以借助SQL CLR函数来实现,代码如下。
1 List<int> productIds = new List<int> 2 { 3 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 4 }; 5 using (var db = new PackageFHContext()) 6 { 7 var joinResult = from p in db.ProductMasterSet 8 join c in db.CLR_Split(string.Join(",", productIds), ",", true) on p.ProductID.ToString() equals c.id 9 select p; 10 }
这里使用了SQL CLR的Split函数将list处理成一个表后再关联过滤的,生成的SQL语句如下。
Select …… FROM [dbo].[Pkg_ProductMaster] AS [Extent1] INNER JOIN [dbo].[CLR_Split](@input, @delimiter, @isRemoveEmptyEntries) AS [Extent2] ON CAST( [Extent1].[ProductID] AS nvarchar(max)) = [Extent2].[id] WHERE 58 = [Extent1].[DepartureCityID];