使用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分钟以上运行。
为什么会这样,包括列时运行得更快?
我尝试了所有方法以清除现金并多次运行,并且结果相同
答案 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
即可添加引用该索引的查询索引视图。