一尘不染

为什么尽管索引了有序列,但我的SQL Server ORDER BY还是很慢?

sql

我有一个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

该查询返回大约1200行,我认为这不是一个很大的行。不幸的是,这也需要约16秒。如果没有ORDER BY,查询将花费不到1秒的时间。

我已经使用SQL Server Management Studio在startDatetime列上添加了索引,还在“
cityId,industryId,startDatetime,positionTypeId,payPerId,stateId”(即我们在“作业”中使用的所有列)上创建了聚集索引。联接和在列上我们使用ORDER
BY on)。我已经在JOIN中使用的每个列上都有单独的索引。不幸的是,这并没有使查询更快。

我运行了一个展示计划,并得到:

   |--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)

重要的一行似乎是“ | –Sort(ORDER BY:([mydb]。[dbo]。[jobs]。[issueDatetime] ASC)))”
―在该列上未提及任何索引。

为什么我的ORDER BY使查询变慢得多,如何加快查询速度?


阅读 189

收藏
2021-03-17

共1个答案

一尘不染

如果您的查询之前不包含订单,则它将以找到的顺序返回数据。不能保证再次运行查询时,数据甚至会以相同的顺序返回。

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

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

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

2021-03-17