create table dbo.Parent ( Id bigint NOT NULL, TypeId int NOT NULL ) create table dbo.Child ( Id bigint NOT NULL, ParentId bigint NOT NULL, TypeId int NOT NULL, varcharColumn varchar(300) NULL ) select cast(c.varcharColumn as int) from dbo.Parent p (nolock) inner join dbo.Child c (nolock) on p.Id = c.ParentId and c.TypeId = 2 where p.TypeId = 13
由于无法将其转换为int的值,因此发生了强制转换。在这种情况下:“ 123-1”。奇怪的是,要转换的值会从最终结果集中过滤掉。
select c.varcharColumn from dbo.Parent p (nolock) inner join dbo.Child c (nolock) on p.Id = c.ParentId and c.TypeId = 2 where p.TypeId = 13 and c.varcharColumn = '123-1'
查询计划最终查看了子表,并在where子句之前实际应用了强制转换功能。
我们能够通过在子表上创建新索引来解决此问题(它正在执行PK 扫描 )
create index [NCIDX_dbo_Child__TypeId] on dbo.Child ( TypeId ) include ( ParentId, varcharColumn )
现在,它首先过滤父表的where子句。
没有额外的索引,有什么方法可以解决此问题?同样,请避免提出任何与修复我们的架构有关的建议。在这种情况下,这绝对是正确的解决方法。
我最想了解的是为什么它在过滤结果集之前应用了强制类型转换。
谢谢
非常感谢亚伦和戈登。如果我获得超过15个代表点,我会回头再谈您的两个回答。
我们最终需要Gordon的答案,因为我们想在视图中使用此查询。办公室中的一些人对使用案例声明感到谨慎,因为他们希望对确保我们首先拥有较小的结果集(Aaron的答案)有更多的控制权,但是这全都归结为查看查询计划并检查您的阅读结果计数。
再次感谢您的所有答复!
首先,这不是一个“明显的设计问题”。SQL是输出的描述性语言,而不是指定如何进行练习的过程性语言。通常,不能保证处理顺序,这是一个优势。我可能会说存在一个设计问题,但这是有关SQL语句中异常的一般处理。
根据SQL Server文档(http://msdn.microsoft.com/zh-cn/library/ms181765.aspx), 对于标量表达式 ,您可以依赖CASE语句的评估顺序。因此,以下应该工作:
select (case when isnumeric(c.varcharColumn) = 1 then cast(c.varcharColumn as int) end)
或者,更接近“ int”表达式:
select (case when isnumeric(c.varcharColumn) = 1 and c.varcharColumn not like '%.%' and c.varcharColumn not like '%e%' then cast(c.varcharColumn as int) end)
至少您的代码正在执行显式的CAST。当强制转换是隐式的(并且有数百列)时,这种情况更加糟糕。