不相关的列会影响select语句的查询时间吗?

use*_*867 10 performance sql-server select query-performance

我只是好奇。

假设您有一个包含 100 万条记录/行的表。

select order_value from store.orders
Run Code Online (Sandbox Code Playgroud)

那个表有1个字段、2个字段还是100个字段,在实际查询的时候有区别吗?我的意思是“order_value”以外的所有字段。

现在我正在将数据推送到数据仓库。有时我将字段转储到表中,“将来可能会在某天使用” - 但现在不会被任何东西查询。这些“无关”字段是否会直接或间接影响不包含它们的选择语句(不* 我的意思是)?

ype*_*eᵀᴹ 12

这取决于表结构和可用索引。

  • 案例 A:公用(行存储)表,没有索引(order_value)

    唯一可能的执行计划是读取整个表(当它是 2 列和 200 列时,这当然大不相同,所以几对几千字节宽)。

  • 情况 B:公用表,有一个索引(order_value)或其他一些索引包含该列。

    现在有一个更好的计划,扫描整个索引(其中一个)——这当然比整个表窄得多,只有几个字节。如果表有 2 或 200 列,这无关紧要。仅扫描索引。

  • 案例 C:这是一个列存储表。

    顾名思义,这些表的结构是面向列的,而不是面向行的。不需要任何索引,表设计本身适合读取整列。


Eri*_*ing 10

这实际上取决于索引和数据类型。

以 Stack Overflow 数据库为例,Users 表是这样的:

坚果

它在 Id 列上有一个 PK/CX。所以它是按 Id 排序的整个表数据。

有了它作为唯一的索引,SQL 必须将整个内容(没有 LOB 列)读入内存(如果它还没有)。

DBCC DROPCLEANBUFFERS-- Don't run this anywhere near prod.

SET STATISTICS TIME, IO ON 

SELECT u.Id
INTO  #crap1
FROM dbo.Users AS u
Run Code Online (Sandbox Code Playgroud)

统计时间和 io 配置文件如下所示:

Table 'Users'. Scan count 7, logical reads 80846, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2406 ms,  elapsed time = 446 ms.
Run Code Online (Sandbox Code Playgroud)

如果我只在 Id 上添加一个额外的非聚集索引

CREATE INDEX ix_whatever ON dbo.Users (Id)
Run Code Online (Sandbox Code Playgroud)

我现在有一个更小的索引来满足我的查询。

DBCC DROPCLEANBUFFERS-- Don't run this anywhere near prod.

SELECT u.Id
INTO  #crap2
FROM dbo.Users AS u
Run Code Online (Sandbox Code Playgroud)

这里的个人资料:

Table 'Users'. Scan count 7, logical reads 6587, physical reads 0, read-ahead reads 6549, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2344 ms,  elapsed time = 384 ms.
Run Code Online (Sandbox Code Playgroud)

我们能够执行更少的读取并节省一点 CPU 时间。

如果没有关于您的表定义的更多信息,我无法真正尝试重现您想要更好地衡量的内容。

但是您是说除非该单独列上有特定索引,否则其他列/字段也将被扫描?这只是行存储表设计的固有缺点吗?为什么不相关的字段会被扫描?

是的,这是特定于行存储表的。数据按数据页上的行存储。即使页面上的其他数据与您的查询无关,也需要将整行 > 页 > 索引读入内存。我不会说其他列被“扫描”了这么多,因为它们所在的页面被扫描以检索与查询相关的单个值。

使用 ol' 电话簿示例:即使您只是在阅读电话号码,当您翻页时,您也在翻阅姓氏、名字、地址等以及电话号码。