Dan*_*rts 1 sql-server sql-server-2012
昨天我们有一个查询,旨在翻阅结果,但在结果的第一页上,查询只返回 4 条记录,而不是预期的 25 条。以任何方式更改查询都会导致 25 条记录,这对我来说意味着这是一次执行计划问题。我不熟悉在生产中查看执行计划的方法,并且在 sql studio 中运行查询没有导致相同的问题,可能是由于细微的差异。
我阅读了一些建议,认为这种事情可能是由损坏的索引引起的。我在数据库上运行了 checkdb 并没有发现错误。最后我清除了执行计划,一切都很好。
如果它不是某种类型的损坏问题,而只是非常具体的执行计划的问题,那么这是否意味着执行计划中存在错误并且我们在 SQL Server 中遇到了错误?我们在 SQL Server 2012 RTM 上没有更新,所以我查看了累积更新和服务包中所有修复的文档,但没有一个问题似乎与我们自己的相关。
关于可能导致这种情况的任何其他想法或想法?
(@P1 varchar(8000),@P2 bit,@P3 varchar(8000),@P4 bit,@P5 varchar(8000))
SELECT e.*
FROM (
SELECT
TOP 25
ROW_NUMBER() OVER (
ORDER BY AddedDate DESC
) AS Row,
ID
, Prefix
, FirstName
, LastName
, Company
, Address
, City
, State
, Zip
, Country
, WorkPhone
, HomePhone
, MobilePhone
, Email
, MailingLists
, AddedDate
, AwaitingOptin
, OptInDate
, Processed
, ProcessedDate
, Deleted
, Source
, GRRecID
, DatabaseID
, (SELECT COUNT(*)
FROM TableA
LEFT OUTER JOIN TableB ON TableA.GRRecID = TableB.GRRecID
WHERE TableA.AccountID = @P1
AND TableA.Email = TableC.Email
AND TableA.Deleted = @P2
) AS Matches
FROM TableC
WHERE AccountID = @P3
AND Processed = @P4
AND Deleted = 0
AND Source = @P5
) AS e
WHERE Row >= 1 AND Row <= 25
ORDER BY Row
Run Code Online (Sandbox Code Playgroud)
Mik*_*son 10
我不相信结果是不正确的,您的查询不明确。从语义上讲,您的子查询枚举所有行,然后您选择前 25 行而不指定 order by。这意味着 SQL Server 可以自由地返回它感觉的任何行,并且这些行不必是枚举 1 到 25 的行。它可以是任何随机行,在您的情况下,在范围内枚举了四行1 到 25。其余的在主查询中被过滤掉了。
您可以通过删除子查询中的 top 语句来修复查询。
根据您的查询,您认为最好的行动方案是什么?
我会测试您拥有的所有选项,然后选择性能最佳的选项。
我会给你一个更多的测试选项,假设ID
是主键列,TableC
而AddedDate
不是聚集键。
添加一个索引,AddedDate
包括在枚举发生之前您需要过滤掉行的列。
create index IX_TableC_AddedDate on TableC(AddedDate)
include(AccountID, Processed, Deleted, Source)
Run Code Online (Sandbox Code Playgroud)
重写您的子查询,以便唯一返回ID
,row
然后加入TableC
主查询以获取其余列。
SELECT E.Row,
C.*, -- don't use * here, include the columns you actually need
(
SELECT COUNT(*)
FROM TableA as A
LEFT OUTER JOIN TableB AS B
ON A.GRRecID = B.GRRecID
WHERE A.AccountID = @P1 AND
A.Email = C.Email AND
A.Deleted = @P2
) AS Matches
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY C.AddedDate DESC) AS Row,
C.ID
FROM TableC as C
WHERE AccountID = @P3 AND
Processed = @P4 AND
Deleted = 0 AND
Source = @P5
) AS E
INNER JOIN TableC as C -- Join back to TableC
ON E.ID = C.ID
WHERE E.Row >= 1 AND E.Row <= 25
ORDER BY E.Row
Run Code Online (Sandbox Code Playgroud)
您可以尝试使用更有效的索引,但参数的数据类型有些令人困惑。是AccountID
一个真正的VARCHAR(8000)?如果不是,您应该更改数据类型以匹配列的数据类型,在这种情况下,更好的索引使用将导致 with AccountID
。
create index IX_TableC_AccountID_AddedDate on TableC(AccountID, AddedDate)
include(Processed, Deleted, Source)
Run Code Online (Sandbox Code Playgroud)
这同样Source
取决于它是什么数据类型。如果数据类型合适,您也可以AddedDate
在索引的列列表之前添加该数据类型。
如果想避免任何残留谓词,您甚至可以使用索引中 where 子句中的所有列。
create index IX_TableC_ on TableC(AccountID, Source, Processed, Deleted, AddedDate)
Run Code Online (Sandbox Code Playgroud)
只要确保AddedDate
是索引中的最后一列,并且AddedDate
在 where 子句中没有未使用的列之前没有任何列。
Itzik Ben-Gan 发表的一篇关于相同查找问题的博客文章(用于偏移获取):
归档时间: |
|
查看次数: |
951 次 |
最近记录: |