【发布时间】:2017-12-21 22:17:08
【问题描述】:
使用 C# 和 Linq to SQL,我发现我的多个 where 查询比单个 where / and 慢几个数量级。
这里是查询
using (TeradiodeDataContext dc = new TeradiodeDataContext())
{
var filterPartNumberID = 71;
var diodeIDsInBlades = (from bd in dc.BladeDiodes
select bd.DiodeID.Value).Distinct();
var diodesWithTestData = (from t in dc.Tests
join tt in dc.TestTypes on t.TestTypeID equals tt.ID
where tt.DevicePartNumberID == filterPartNumberID
select t.DeviceID.Value).Distinct();
var result = (from d in dc.Diodes
where d.DevicePartNumberID == filterPartNumberID
where diodesWithTestData.Contains(d.ID)
where !diodeIDsInBlades.Contains(d.ID)
orderby d.Name
select d);
var list = result.ToList();
// ~15 seconds
}
但是,当最终查询中的条件是 this 时
where d.DevicePartNumberID == filterPartNumberID
& diodesWithTestData.Contains(d.ID)
& !diodeIDsInBlades.Contains(d.ID)
// milliseconds
速度很快。
在调用ToList()之前比较result中的SQL,这里是查询(手动添加值71代替@params)
-- MULTIPLE WHERE
SELECT [t0].[ID], [t0].[Name], [t0].[M2MID], [t0].[DevicePartNumberID], [t0].[Comments], [t0].[Hold]
FROM [dbo].[Diode] AS [t0]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t2].[value]
FROM (
SELECT [t1].[DiodeID] AS [value]
FROM [dbo].[BladeDiode] AS [t1]
) AS [t2]
) AS [t3]
WHERE [t3].[value] = [t0].[ID]
))) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t6].[value]
FROM (
SELECT [t4].[DeviceID] AS [value], [t5].[DevicePartNumberID]
FROM [dbo].[Test] AS [t4]
INNER JOIN [dbo].[TestType] AS [t5] ON [t4].[TestTypeID] = ([t5].[ID])
) AS [t6]
WHERE [t6].[DevicePartNumberID] = (71)
) AS [t7]
WHERE [t7].[value] = [t0].[ID]
)) AND ([t0].[DevicePartNumberID] = 71)
ORDER BY [t0].[Name]
和
-- SINGLE WHERE
SELECT [t0].[ID], [t0].[Name], [t0].[M2MID], [t0].[DevicePartNumberID], [t0].[Comments], [t0].[Hold]
FROM [dbo].[Diode] AS [t0]
WHERE ([t0].[DevicePartNumberID] = 71) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t3].[value]
FROM (
SELECT [t1].[DeviceID] AS [value], [t2].[DevicePartNumberID]
FROM [dbo].[Test] AS [t1]
INNER JOIN [dbo].[TestType] AS [t2] ON [t1].[TestTypeID] = ([t2].[ID])
) AS [t3]
WHERE [t3].[DevicePartNumberID] = (71)
) AS [t4]
WHERE [t4].[value] = [t0].[ID]
)) AND (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t6].[value]
FROM (
SELECT [t5].[DiodeID] AS [value]
FROM [dbo].[BladeDiode] AS [t5]
) AS [t6]
) AS [t7]
WHERE [t7].[value] = [t0].[ID]
)))
ORDER BY [t0].[Name]
两个 SQL 查询在 SSMS 中的执行时间
所以我想知道为什么第一个在 LINQ 方面较慢。这让我很担心,因为我知道我在其他地方使用了多个where,却没有意识到对性能的影响如此严重。
This question 甚至回答了多个 & 和 where。 this answer 甚至建议使用多个 where 子句。
谁能解释我的情况为什么会这样?
【问题讨论】:
-
你需要看一下执行计划。但是,查看 2 个查询,第 2 个查询(单个 where)首先搜索
[t0].[DevicePartNumberID] = 71,然后执行其他条件。第一个查询执行所有其他查询(相关查询),然后查找[t0].[DevicePartNumberID] = 71。这正是我从代码中看到的。有可能我错了,生成的计划与我说的完全不同。 -
你不会手写这个,所以不要让 ORM 为你做。尽量避免使用连接的嵌套选择(避免 .contains)。这将使生成的sql更简单更快
-
您的意思是将
&放在第二个条件而不是&&吗? -
@GeorgeVovos 请解释您避免使用 .contains 的原因。 ORM 的理念是人们不应该关心 ORM 生成了什么代码:如果事情很慢,那么您可以查看它以查看生成的内容并查看是否可以改进。否则,在应用程序端编写的代码会被开发人员读取,因此代码应该以易于阅读的方式编写(无论 ORM 输出什么内容)。
-
@CodingYoshi ORM 的想法是人们不应该关心 ORM 生成什么代码:这是完全错误的(对于 ORM 和任何其他工具)。我不是在谈论包含是通用的,而是在谈论具体示例。如果 OP 删除了diodeIDsInBlades 和diodesWithTestData 变量,则主查询中的使用连接可能会产生更高效的sql
标签: c# sql-server linq linq-to-sql .net-4.7