Sql 未从视图中选择特定列时性能不佳

Sql 未从视图中选择特定列时性能不佳,sql,sql-server,tsql,Sql,Sql Server,Tsql,使用SQL Server 2016 SP1。我有一个用户的视图 SELECT ROW_NUMBER() OVER (ORDER BY ID) AS DataModelID, * FROM (Some query) AS tbl 然后我从中选择 SELECT U1.ID UserId, U1.IdentityNumber IdentityNumber, U1.ArabicFirstName, U1.ArabicSecondName FRO

使用SQL Server 2016 SP1。我有一个用户的视图

SELECT
    ROW_NUMBER() OVER (ORDER BY ID) AS DataModelID, *
FROM            
    (Some query) AS tbl
然后我从中选择

SELECT 
    U1.ID UserId, U1.IdentityNumber IdentityNumber,
    U1.ArabicFirstName, U1.ArabicSecondName
FROM
    USERS U1
LEFT JOIN 
    USERS U2 ON U1.IdentityNumber = U2.IdentityNumber
             AND U1.ID <> U2.ID
             AND U1.RoleId = 2
WHERE 
    U2.ID IS NOT NULL 
    AND U1.IdentityNumber <> '' 
    AND PATINDEX('[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]', U1.IdentityNumber) = 1
这里的问题是,当选择*或包含列DataModelID时,上面的查询将在3秒内运行,但当选择没有此查询的任何列时,它将在2分钟以上运行

为什么会出现这种情况,在包含列时运行得更快

我尝试了所有的方法来清除它,并运行了多次,结果都是一样的

,但没有看到实际的执行计划。没有办法确定,但正如@mvisser所提到的,可能的原因是优化器在执行一个优化时选择了一个更好的索引 选择*或包含列DataModelID,而不是不选择。这里有许多解决方案,其中一个建议是查看在3秒内运行的查询的执行计划,注意正在使用的索引,并使用see see section G强制优化器在不引用这些列的查询中使用该索引。我不会建议这一点-有太多的未回答的变量来考虑这是一个可行的选择。 以下是我的建议:

首先,正如@Lukasz Szozda提到的,这不是SARGable:

AND PATINDEX( '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]',U1.IdentityNumber) = 1
但这是:

U1.IdentityNumber LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
所以我会先解决这个问题。接下来,解决这个问题的最快、最可靠的方法是在查询中简单地包含DataModelID,即使您不需要它们。您可以在应用程序级别筛选该列,也可以创建一个存储的过程来填充临时表,然后,对于最终结果集,您可以从该临时表(不包括DataModelID)检索结果

选择2

您可以在用户表上创建一个索引视图,如下所示:

CREATE VIEW dbo.vwUSERS_clean
WITH SCHEMABINDING AS
SELECT U1.ID, UserId, U1.IdentityNumber IdentityNumber,
       U1.ArabicFirstName, U1.ArabicSecondName, DataModelID, U2.IdentityNumber
FROM USERS U1
WHERE U2.ID IS NOT NULL 
AND U1.IdentityNumber <> '' 
AND U1.IdentityNumber LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]';
GO
然后在其上创建一个唯一的聚集索引。接下来,您将更改发布以引用索引视图的查询,例如,将对用户的两个引用都更改为dbo.vwUSERS\u clean WITH NOEXPAND


请注意,索引视图中不允许使用行\号,但是,如果将ID设置为聚集索引或复合聚集索引中的第一列,则向引用该索引视图的查询中添加超过ORDER BY ID的行\号不会产生任何成本

为了快速缓解压力,您可能需要检查SSMS中的查询计划。很可能SQL Optimizer正在使用不同的索引。您可以向我们展示这两个查询的执行计划吗?如果您的外部查询都是这样做的,那么您可能不需要在子查询之外有行号。您应该能够在查询本身内部执行窗口功能。而PATINDEX“[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]”,U1.IdentityNumber=1不是Sargableth此U2.ID不是NULL会将左连接变为内部连接,出于性能原因,首选第二个。而U1.RoleId=2在连接谓词中是混乱的-它与连接条件无关,所以应该放在WHERE子句中