SQL Server中的分页


17

我有一个非常大的数据库,大约100 GB。我正在执行查询:

select * from <table_name>;

我只想显示第100至200行。

我想了解内部情况。数据库是否将所有记录从磁盘中提取到内存中,然后将第100至400行发送回查询客户端?还是存在任何机制,以便仅使用B树等索引机制从数据库中提取那些记录(第100个-200个)?

我发现这与分页概念有关,但是我无法确切找到它在数据库级别内部如何发生。

Answers:


37

在您发布的查询中:

select * from <table_name>;

没有第100-200行这样的事情,因为您没有指定ORDER BY。除非您出于很多有趣的原因将ORDER BY包括在内,否则无法保证订购,但这并不是重点。

为了说明您的观点,我们使用一个表-我将使用Stack Overflow数据转储中的Users表,并运行以下查询:

SELECT * FROM dbo.Users ORDER BY DisplayName;

默认情况下,DisplayName字段上没有索引,因此SQL Server必须扫描整个表,然后按DisplayName对其进行排序。这是执行计划

排序的聚集索引扫描

它不是很漂亮-需要大量工作,估计子树成本约为3万。(您可以通过将鼠标悬停在PasteThePlan上的select运算符上来查看它。)那么,如果我们只希望100-200行会发生什么?我们可以在SQL Server 2012+中使用以下语法:

SELECT * FROM dbo.Users ORDER BY DisplayName OFFSET 100 ROWS FETCH NEXT 100 ROWS ONLY;

那的执行计划也很丑陋:

具有排序和顶部的聚簇索引扫描

SQL Server仍在扫描整个表以构建排序列表,仅使您的行数为100-200,而成本仍然约为30k。更糟糕的是,每次查询运行时都会重新构建整个列表(因为毕竟可能有人更改了其DisplayName。)

为了使其运行更快,我们可以在DisplayName上创建一个非聚集索引,该索引是表的副本,并按该特定字段排序:

CREATE INDEX IX_DisplayName ON dbo.Users(DisplayName);

使用该索引,我们的查询的执行计划现在执行索引查找:

索引查找和关键查找

该查询将立即完成,并且估计的子树成本仅为0.66(而不是30k)。

总之,如果您以支持您经常运行的查询的方式组织数据,那么可以,SQL Server可以使用快捷方式来使查询运行得更快。另一方面,如果您只有堆或聚集索引,那么您就搞砸了。


“默认情况下,DisplayName字段上没有索引,因此SQL Server必须扫描整个表,然后按DisplayName对其进行排序。”如果这是一个非常基本的问题,请原谅我-如果我引用了您的回答,说“扫描整个表”,是否意味着所有数据都被带入内存并进行了排序(看起来不太正确)?
AV94

从您的答案中,我了解到,如果对该字段进行了索引,则进行查询-获得第100至200行非常有效,因为SQL查找索引(B树等)并直接转到该点(第100行)。你能告诉我这是否是正确的理解吗?
AV94

@AnilVedala关于您的第一个问题-是的,必须对数据进行排序。数据库还可以通过未排序的列表来完成该任务吗?
布伦特·奥扎尔

1
@AnilVedala关于第二个问题-那是我给您的最后一个执行计划。(如果您要问如何阅读执行计划,请阅读Grant Fritchey撰写的《执行计划》。)
Brent Ozar

15

正如使用非覆盖索引来避免排序时对Brent答案的补充一样,可以通过运行以下命令看到更高的页码潜在问题

SELECT * 
FROM dbo.Users 
ORDER BY DisplayName 
OFFSET 100000 ROWS 
FETCH NEXT 100 ROWS ONLY;

执行计划显示,即使TOP运算符随后过滤了除100行之外的所有行,该查询已执行了100,100次。

在此处输入图片说明

可以使用以下模式来缓解

WITH T
     AS (SELECT Id,
                DisplayName
         FROM   dbo.Users
         ORDER  BY DisplayName
        OFFSET 100000 ROWS 
        FETCH NEXT 100 ROWS ONLY
        )
SELECT U.*
FROM   dbo.Users U
       JOIN T
         ON U.Id = T.Id
ORDER  BY T.DisplayName 

这会执行查找之前过滤掉除最后100行之外的所有行这可能会对大偏移量的速度产生重大影响。

在此处输入图片说明


3

这实际上取决于您如何在查询中实现分页,数据的性质以及系统的配置方式。可以肯定地说,SQL Server将尝试以最少的努力返回您的数据。如果您没有明确的排序顺序,过滤,分组或任何窗口设置,则SQL Server可能会优化查询计划,使其可以仅从磁盘中返回包含查询所需数据的页面,甚至更好的是直接从磁盘中返回页面。缓冲池。一旦开始更改查询以包括排序,分组,开窗和过滤,查询就会变得复杂。

有关于SQL性能非常不错的文章在这里是进入的分页的各种方法,以及它们如何影响查询计划的一些细节。我强烈建议您阅读它,然后尝试他们指出的各种方法中的一些,并查看在您自己的系统上选择了哪种查询计划。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.