作为一个警告,我正在使用从实体框架生成的SQL查询,但是实体框架与该问题无关。
某些情况: 我正在尝试从一批4,000个C#对象中提取特定记录,并对其执行更新或插入操作。我没有记录的主键,因为对象来自API,所以我必须使用一组唯一的列来提取正确的记录。
(简化的)查询及其执行计划:
参数化查询(出于演示目的,将参数声明为1)
SELECT [x].[Id]
FROM [Gradebook].[AssignmentScore] AS [x]
WHERE
( ( ((([x].[CourseSectionAssignment_Id] = @__CSA_1) AND ([x].[Student_Id] = @__S_ID_1)) AND ([x].[AssessmentGBID] = @__A_GBID_1))
OR ((([x].[CourseSectionAssignment_Id] = @__CSA_2) AND ([x].[Student_Id] = @__S_ID_2)) AND ([x].[AssessmentGBID] = @__A_GBID_2)) )
OR ((([x].[CourseSectionAssignment_Id] = @__CSA_3) AND ([x].[Student_Id] = @__S_ID_3)) AND ([x].[AssessmentGBID] = @__A_GBID_3)) )
这是(不利的)执行计划:
文字值查询:
SELECT [x].[Id]
FROM [Gradebook].[AssignmentScore] AS [x]
WHERE
( ( ((([x].[CourseSectionAssignment_Id] = 1) AND ([x].[Student_Id] = 2)) AND ([x].[AssessmentGBID] = 3))
OR ((([x].[CourseSectionAssignment_Id] = 4) AND ([x].[Student_Id] = 5)) AND ([x].[AssessmentGBID] = 6)) )
OR ((([x].[CourseSectionAssignment_Id] = 7) AND ([x].[Student_Id] = 8)) AND ([x].[AssessmentGBID] = 9)) )
这是(有利的)执行计划:
我知道为什么,或者至少我相信为什么,执行计划是不同的。那是因为优化器不知道参数是否为NULL,必须围绕这种情况进行优化。使用NULL测试文字查询会创建不利的执行计划。 (为什么参数嗅探不会看到值不为null并创建更好的执行计划?)
当前,在C#代码中,我正在手动使用表达式树用表达式常量替换对象的属性,以便生成的查询是文字查询。据我所知,文字会强制SQL Server每次生成一个新的执行计划,这并不好。
我希望参数化查询生成有利的执行计划。到目前为止,我发现的唯一答案是使用OPTION(RECOMPILE)
提示,这并不是我想要的,因为它会强制重新创建执行计划。
每次使用参数化查询时,如何使用相同的有利执行计划?
答案 0 :(得分:1)
根据我的经验,如果无法解决不良索引的问题,这将始终产生良好的执行计划。
SELECT [x].[Id]
FROM [Gradebook].[AssignmentScore] AS [x]
WHERE [x].[CourseSectionAssignment_Id] = 1
AND [x].[Student_Id] = 2
AND [x].[AssessmentGBID] = 3
UNION
SELECT [x].[Id]
FROM [Gradebook].[AssignmentScore] AS [x]
WHERE [x].[CourseSectionAssignment_Id] = 4
AND [x].[Student_Id] = 5
AND [x].[AssessmentGBID] = 6
UNION
SELECT [x].[Id]
FROM [Gradebook].[AssignmentScore] AS [x]
WHERE [x].[CourseSectionAssignment_Id] = 7
AND [x].[Student_Id] = 8
AND [x].[AssessmentGBID] = 9
或者,您可以使用“有效”组合创建一个临时表,然后在这三个字段上简单地将其联接。