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

时间:2018-09-04 14:30:57

标签: sql sql-server tsql

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

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分钟以上运行。

为什么会这样,包括列时运行得更快?

我尝试了所有方法以清除现金并多次运行,并且结果相同

1 个答案:

答案 0 :(得分:0)

没有看到actual执行计划,就无法确定,但是正如@mvisser所提到的那样-可能的原因是,当您执行优化操作时,优化器正在选择更好的索引 SELECT *或包含列DataModelID(而不是列)。这里有许多解决方案,一个建议是查看3秒内运行的查询的执行计划,注意正在使用的索引,并使用index hint(请参阅G部分)来强制优化器在不引用这些列的查询中使用该索引。 我不建议这样做-有太多未解决的变量,无法将其视为可行的选择。

这是我的建议:

首先,就像@Lukasz Szozda提到的那样,这是不可行的:

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

您可以在USERS表上创建索引视图,如下所示:

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

然后在其上创建唯一的聚集索引。接下来,您将更改发布的查询以引用索引视图(例如,将两个引用从USERS更改为dbo.vwUSERS_clean WITH (NOEXPAND) )。

请注意,索引视图中不允许ROW_NUMBER,但是,如果您以ID为聚集索引(或复合聚集索引的第一列),则无需花费ROW_NUMBER() OVER ORDER BY ID即可添加引用该索引的查询索引视图。