列数会影响查询性能吗?
Posted
技术标签:
【中文标题】列数会影响查询性能吗?【英文标题】:Does the number of columns affect query performance? 【发布时间】:2011-04-09 17:15:57 【问题描述】:案例 1:我有一个包含 30 列的表,我在 where 子句中使用 4 列进行查询。
案例 2:我有一个包含 6 列的表,我在 where 子句中使用 4 列进行查询。
这两种情况下的性能有何不同?
例如我有桌子
table A
b varchar(10),
c varchar(10),
d varchar(10),
e varchar(10),
f varchar(10),
g varchar(10),
h varchar(10)
SELECT b,c,d
FROM A
WHERE f='foo'
create table B
b varchar(10),
c varchar(10),
d varchar(10),
e varchar(10),
f varchar(10)
SELECT b,c,d
FROM B
WHERE f='foo'
A 和 B 表具有相同的结构,仅表示列数和使用的列数不同,其中条件也相同,选择中的列也相同。区别在于表 B 只有一些未使用的列,这些列没有在 select 和 where 条件中使用 在这种情况下,两个查询的性能有什么不同吗?
【问题讨论】:
【参考方案1】:表中的总列数是否会影响性能(如果选择了相同的列子集,并且表上没有索引)
是的,勉强,完全没有索引,两个查询(表 A 和表 B)都会进行表扫描。鉴于Table B
的列数比Table A
少,B
上每页的行数(密度)会更高,因此B
会稍微快一些,因为需要获取的页面更少。
但是,鉴于您的查询是以下形式:
SELECT b,c,d
FROM X
WHERE f='foo';
查询的性能将取决于列 f
的索引,而不是基础表中的列数。
对于 OP 的精确查询,最快的性能将来自以下索引:
A(f) INCLUDE (b,c,d)
上的索引
B(f) INCLUDE (b,c,d)
上的索引
无论表 A 或表 B 中的列数如何,在上述索引到位的情况下,两个查询的性能应该相同(假设两个表中的行数和数据相似),因为 SQL 会命中现在具有相似列宽和行密度的索引,不需要原始表中的任何其他数据。
select 中的列数会影响查询性能吗?
在SELECT
中返回较少列的主要好处是SQL 可能能够避免从表/集群中读取,而是如果它可以检索所有selected
数据来自 index(在 covering index 的情况下作为索引列和/或包含列)。
显然,谓词(where filter)中使用的列,即您的示例中的f
,必须在索引的索引列中,并且数据分布必须足够@987654322 @,以便首先使用索引。
从SELECT
返回更少的列还有一个次要好处,因为这将减少任何 I/O 开销,尤其是在数据库服务器和应用程序之间的网络速度较慢的情况下使用数据 - 即最好只返回您实际需要的列,并避免使用SELECT *
。
编辑
其他一些计划:
B(f)
上的索引没有其他键或INCLUDE
列,或具有一组不完整的INCLUDE
列(即缺少一个或多个b, c or d
):
SQL Server 可能需要执行Key or RIDLookup,因为即使使用了索引,也需要“加入”回表以检索 select 子句中丢失的列。 (查找类型取决于表是否有聚簇PK)
B(f,b,c,d)
上的直接非聚集索引
这仍然会非常高效,因为将使用索引并避免使用表,但是won't be quite as good as the covering index,因为索引中的附加键列会降低索引树的密度。
【讨论】:
他并没有询问选择更多列...当然这会影响性能。他问表中有更多列会降低性能吗? @Anthony 都在索引和页面密度中。如果所选列的子集与较窄的非聚集索引或覆盖索引匹配,则可以完全避免实际的“表”。 那么一个 56 列的表是否会显着影响查询的执行时间?通常我很可能会一次选择所有数据 @StuartLC 如果它不会引起问题,该表甚至可能有 110 列,但其中 54 列可能是小数(3,0)或 varchar(3) @Anthony 我已经移动了答案的顺序,以便“未编入索引”的答案排在第一位。但是,两个 OP 查询的性能将由对过滤列的索引(在 OP 的情况下为f
)支配。在表设计期间,将表的列拆分为“部分表”以使页面更窄,而不是将同一表实体的所有逻辑相关的 4NF 列保持在一起是非常激烈的。如果真的到了那个地步,与其搞乱逻辑表设计,不如看一下外部 NoSql 缓存替代方案,如 Redis 等,以获得令人眼花缭乱的性能。【参考方案2】:
测试一下看看!
会有性能差异,但是 99% 的时间您不会注意到它 - 通常您甚至无法检测到它!
您甚至无法保证列数较少的表格会更快 - 如果它困扰您,请尝试看看。
技术垃圾:(从 Microsoft SQL Server 的角度来看)
假设在所有其他方面(索引、行数、6 个公共列中包含的数据等...)这些表是相同的,那么唯一真正的区别是更大的表分布在更多的磁盘/内存中的页面。
SQL 服务器只尝试读取它绝对需要的数据,但它总是一次加载整个页面 (8 KB)。即使需要与查询输出完全相同数量的数据,如果该数据分布在更多页面上,则需要更多 IO。
也就是说,SQL Server 的数据访问效率非常高,因此除非在极端情况下,否则您不太可能看到对性能的显着影响。
此外,您的查询也很可能会针对索引而不是表运行,因此对于完全相同大小的索引,更改可能为 0。
【讨论】:
【参考方案3】:除非您有一个非常宽的列集差异并且没有使用索引(因此是表扫描),否则您应该会发现性能差异不大。话虽如此,返回尽可能少的列以满足您的需求总是有用/有益的。这里要注意的是,通过返回您需要的列而不是为其他列进行第二次数据库提取,可以获得更大的好处。
得到你需要的东西 避免在同一表上针对同一行进行第二次数据库查询 在选择列上使用索引(WHERE 子句限制器) 如果您不需要列以提高数据服务器内存效率/分页,请限制列【讨论】:
这就是说,SQL Server 有时会在内存中抓取整个表/索引然后运行它,这会使列号静音 - 试图找到引用。【参考方案4】:不会有基于列位置的性能差异。现在桌子的构造是一个不同的故事,例如行数、索引、列数等。
你所说的比较两个表中列位置的场景就像比较苹果和橙子一样,因为除了列位置之外还有很多不同的变量。
【讨论】:
【参考方案5】:取决于表的宽度(每行字节数)、表中有多少行以及查询使用的列上是否有索引。没有这些信息就没有明确的答案。但是,表中的列越多,它就越宽。但是合适的索引的效果比表大小的效果要显着。
【讨论】:
【参考方案6】:由于您指定使用 WHERE 子句,它将取决于返回的行数。如果 WHERE 子句中的值是 UNIQUE 或 PRIMARY KEY,则几乎不存在差异。 您可以在 SELECT 语句前面使用 EXPLAIN ANALYZE 来查看计划时间和执行时间值,然后可以比较您的查询。
【讨论】:
以上是关于列数会影响查询性能吗?的主要内容,如果未能解决你的问题,请参考以下文章
使用 TinyInt 还是 Bit 对 SQL Server 有影响吗?大小和查询性能