我有一个非常简单的一个表查询,需要很多秒才能完成。我感到很困惑。当我从select top更改为50而不是200时,它会更快。该表有大约一百万行。
我在所有提到的列上都有索引。
SELECT TOP 50 dbo.EmailDetails.Id,
FROM dbo.EmailDetails WITH (NOLOCK)
WHERE (dbo.EmailDetails.EmailSendStatus = 'NEEDTOSEND' OR
dbo.EmailDetails.EmailSendStatus = 'NEEDTOTEXT') AND
dbo.EmailDetails.EmailDetailsTopicId IS NOT NULL
ORDER BY dbo.EmailDetails.EmailSendPriority,
dbo.EmailDetails.Id DESC
计划生成是:
并且完整DDL是:
CREATE TABLE dbo.EmailDetails (
Id int IDENTITY(1, 1) NOT NULL,
AttendeesId int NOT NULL,
SponsorListContactId int NULL,
MessageUniqueId nvarchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
EmailSendStatus nvarchar(16) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
EmailSendStartTime datetime NULL,
EmailSendFinishTime datetime NULL,
EmailSendLogMessage nvarchar(max) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
Subject nvarchar(2048) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
BodyText nvarchar(max) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
SentDateTime datetime NULL,
EmailFrom nvarchar(128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
EmailTo nvarchar(128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
EmailDetailsTopicId int NULL,
EmailDetailsGuid uniqueidentifier NULL,
EmailReadCount int NULL,
EmailReadDate datetime NULL,
EmailSendStatusChange datetime NULL,
EmailSendPriority int NULL,
TextTo varchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT EmailDetails_pk PRIMARY KEY CLUSTERED (Id)
WITH (
PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, STATISTICS_NORECOMPUTE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_AttendeesIds_idx ON dbo.EmailDetails
(AttendeesId)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_idx ON dbo.EmailDetails
(EmailDetailsGuid)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_idx2 ON dbo.EmailDetails
(EmailDetailsTopicId)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_idx3 ON dbo.EmailDetails
(SentDateTime)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_priority_status_idx4 ON dbo.EmailDetails
(EmailSendPriority, EmailSendStatus)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_SentStatus_idx ON dbo.EmailDetails
(EmailSendStatus)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_topicid_attendeeid ON dbo.EmailDetails
(EmailDetailsTopicId, AttendeesId)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX EmailDetails_topicid_sponsorcontactid_idx ON dbo.EmailDetails
(EmailDetailsTopicId, SponsorListContactId)
WITH (
PAD_INDEX = OFF,
DROP_EXISTING = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
答案 0 :(得分:2)
虽然建议将SELECT TOP x
与ORDER BY
一起使用以确保每次都能获得相同的结果,ORDER BY
会对整个结果集进行排序,然后才会对TOP x进行排序从它。
我想知道如果你做SELECT COUNT(*)
而不是SELECT TOP x
,你会看到什么:可能是一个相当高的数字?
虽然使用索引可以保证快速排序,但 no 索引涵盖了此查询的确切ORDER BY。最重要的是,获取WHERE和SELECT子句的字段需要进入可能遍布整个磁盘的数据页。要优化此查询,您可以将WHERE-和ORDER BY-和SELECT-字段添加到新索引(按此顺序),当然不需要重复。它会产生一个相当大的索引,这可能会减慢插入/更新速度,但它也会使SELECT非常快,因为只需使用索引就可以满足整个查询,而无需进入数据页。