尽管有序列被索引,为什么我的SQL Server ORDER BY会变慢?

Geo*_*rge 16 sql sql-server linq-to-entities sql-server-2005

我有一个SQL查询(由LINQ to Entities生成),大致如下所示:

SELECT * FROM [mydb].[dbo].[employees]
JOIN [mydb].[dbo].[industry]
  ON jobs.industryId = industry.id
JOIN [mydb].[dbo].[state]
  ON jobs.stateId = state.id
JOIN [mydb].[dbo].[positionType]
  ON jobs.positionTypeId = positionType.id
JOIN [mydb].[dbo].[payPer]
  ON jobs.salaryPerId = payPer.id
JOIN [mydb].[dbo].[country]
  ON jobs.countryId = country.id
WHERE countryName = 'US'
ORDER BY startDatetime
Run Code Online (Sandbox Code Playgroud)

查询返回大约1200行,我认为这不是一个巨大的数额.不幸的是,它还需要大约16秒.如果没有ORDER BY,查询将花费<1秒.

我已经使用SQL Server Management Studio在startDatetime列上添加索引,并在"cityId,industryId,startDatetime,positionTypeId,payPerId,stateId"上使用聚簇索引(即我们在"作业"中使用的所有列JOIN和我们使用ORDER BY的列.)我已经在JOIN中使用的每个列上都有单独的索引.不幸的是,这并没有使查询更快.

我跑了一个showplan得到了:

   |--Nested Loops(Inner Join, OUTER REFERENCES:([mydb].[dbo].[jobs].[cityId]))
       |--Nested Loops(Inner Join, OUTER REFERENCES:([mydb].[dbo].[jobs].[stateId]))
       |    |--Nested Loops(Inner Join, OUTER REFERENCES:([mydb].[dbo].[jobs].[industryId]))
       |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([mydb].[dbo].[jobs].[positionTypeId]))
       |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([mydb].[dbo].[jobs].[salaryPerId]))
       |    |    |    |    |--Sort(ORDER BY:([mydb].[dbo].[jobs].[issueDatetime] ASC))
       |    |    |    |    |    |--Hash Match(Inner Join, HASH:([mydb].[dbo].[currency].[id])=([mydb].[dbo].[jobs].[salaryCurrencyId]))
       |    |    |    |    |         |--Index Scan(OBJECT:([mydb].[dbo].[currency].[IX_currency]))
       |    |    |    |    |         |--Nested Loops(Inner Join, WHERE:([mydb].[dbo].[jobs].[countryId]=[mydb].[dbo].[country].[id]))
       |    |    |    |    |              |--Index Seek(OBJECT:([mydb].[dbo].[country].[IX_country]), SEEK:([mydb].[dbo].[country].[countryName]='US') ORDERED FORWARD)
       |    |    |    |    |              |--Clustered Index Scan(OBJECT:([mydb].[dbo].[jobs].[PK_jobs]))
       |    |    |    |    |--Clustered Index Seek(OBJECT:([mydb].[dbo].[payPer].[PK_payPer]), SEEK:([mydb].[dbo].[payPer].[id]=[mydb].[dbo].[jobs].[salaryPerId]) ORDERED FORWARD)
       |    |    |    |--Clustered Index Seek(OBJECT:([mydb].[dbo].[positionType].[PK_positionType]), SEEK:([mydb].[dbo].[positionType].[id]=[mydb].[dbo].[jobs].[positionTypeId]) ORDERED FORWARD)
       |    |    |--Clustered Index Seek(OBJECT:([mydb].[dbo].[industry].[PK_industry]), SEEK:([mydb].[dbo].[industry].[id]=[mydb].[dbo].[jobs].[industryId]) ORDERED FORWARD)
       |    |--Clustered Index Seek(OBJECT:([mydb].[dbo].[state].[PK_state]), SEEK:([mydb].[dbo].[state].[id]=[mydb].[dbo].[jobs].[stateId]) ORDERED FORWARD)
       |--Clustered Index Seek(OBJECT:([mydb].[dbo].[city].[PK_city]), SEEK:([mydb].[dbo].[city].[id]=[mydb].[dbo].[jobs].[cityId]) ORDERED FORWARD)
Run Code Online (Sandbox Code Playgroud)

重要的一行似乎是"| - 排序(ORDER BY :( [mydb].[dbo].[jobs].[issueDatetime] ASC))" - 没有提到该列的索引.

为什么我的ORDER BY使我的查询变得如此慢,我怎样才能加快查询速度?

Sco*_*uns 13

如果您的查询在那时不包含订单,那么它将返回找到的任何数据.再次运行查询时,无法保证数据甚至会以相同的顺序返回.

当您包含order by子句时,dabatase必须按正确的顺序构建行列表,然后按该顺序返回数据.这可能需要大量额外的处理,这转化为额外的时间.

对您的查询可能返回的大量列进行排序可能需要更长的时间.在某些时候,你将耗尽缓冲区空间,数据库必须开始交换,并且性能将下降.

尝试返回较少的列(指定所需的列而不是Select*)并查看查询是否运行得更快.


Rem*_*anu 7

因为您的查询会投影所有列(*),所以连接条件需要5列,并且对于WHERE可能是连接表列的内容具有非选择性子句,它会使其达到索引引爆点:优化程序决定它的成本更低扫描整个表,对其进行过滤并对其进行排序,以便对索引进行范围扫描,然后查找表中的每个键以检索所需的额外列(连接为5,其余为列*).

部分覆盖此查询的更好的索引可能是:

CREATE INDEX ... ON .. (countryId, startDatetime);
Run Code Online (Sandbox Code Playgroud)

Jeffrey提出的建立聚簇索引的建议将覆盖100%的查询并肯定会提高性能,但更改聚簇索引会产生许多副作用.我将从上面的非聚集索引开始.除非其他查询需要它们,否则您可以删除您创建的所有其他非聚集索引,它们将无法帮助此查询.