select count()效率比较和分析

在数据库查询优化中,看到有人说Count(*)比count(1)快。

猜测是与索引选取的列有关,对比查看执行过程,一试便知。


首先明确一点,执行时只会使用一个索引

测试结论如下:

  • count(*)和count(1)无任何差别永远优于count其他字段,无论加不加任何索引
  • count()里面的值可取任意值,与结果无关
  • 加索引显著快于不加索引
  • 主键索引快于普通索引
  • 没有索引时,与列含不含空值无关
  • count选取的列上如果有就用自己的索引,没有则使用默认索引
    (取首个添加的索引,即使存在主键

总结:

只要存在普通索引,count就会使用普通索引,

只存在主键时,count(*)和或ount(1)会使用主键索引,其他字段不会

count(*)和或ount(1)最快


配置

版本:mysql-5.7.23-winx64
CPU:Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz

经多次测试发现用mysql和navicat 效率几乎相同,故采用navicat

这里写图片描述
这里写图片描述
查询500000条数据,


Tips:

  • id字段均不为null
  • test字段均为null

1.没有主键和任何索引

select count(*) from user

OK
时间: 0.24s

select count(1) from user

OK
时间: 0.24s

select count(id) from user

OK
时间: 0.266s

select count(test) from user

OK
时间: 0.265s

多次测试结果均相同

这里写图片描述

查看执行过程,全表扫描

结论1:

不加任何索引情况下

  • count(*)和count(1)无差别
  • 查询速度和count的列是否有空值无关
  • count(列)速度慢于count(*)和count(1)

2.只有id主键

select count(*) from user

OK
时间: 0.146s

select count(1) from user

OK
时间: 0.145s

select count(id) from user

OK
时间: 0.158s

select count(test) from user

OK
时间: 0.162s

多次测试结果均相同

这里写图片描述

除了test,都使用了主键索引

结论2:

只使用主键情况下

  • 整体查询速度均有所提升
  • count(*)和count(1)无差别
  • 查询速度和count的列是否有空值有关
  • count(列)速度慢于count(*)和count(1)

3.只有索引

select count(*) from user

OK
时间: 0.234s

select count(1) from user

OK
时间: 0.233s

select count(id) from user

OK
时间: 0.247s

select count(test) from user

OK
时间: 0.268s

多次测试结果均相同

这里写图片描述

除了test,都使用了id的索引

结论3:

只有索引情况下

  • 和无索引相比,count(*)和count(1)和加索引的列速度提升
  • 但慢于主键
  • count(*)和count(1)无差别
  • 查询速度和count的列是否有空值有关
  • count(列)速度慢于count(*)和count(1)

4.同时存在主键和索引

select count(*) from user

OK
时间: 0.122s

select count(1) from user

OK
时间: 0.121s

select count(id) from user

OK
时间: 0.134s

select count(test) from user

OK
时间: 0.14s

多次测试结果均相同
这里写图片描述

全部使用自定义索引,而没有使用主键索引

结论4:

同时存在主键和索引情况下

  • 整体速度最快
  • count(*)和count(1)无差别
  • 查询速度和count的列是否有空值有关
  • count(列)速度慢于count(*)和count(1)

总结

  • count(*)和count(1)无任何差别永远优于其他count,无论加不加任何索引
  • 加索引显著快于不加索引
  • 主键索引快于普通索引
  • 没有索引时,与列含不含空值无关

其他问题1,存在多个索引怎么决定用哪个呢?

实验得知

加多个索引时,count(列),如果存在就用自己的索引
不存在则使用默认索引,按测试结果是默认的索引添加顺序。

<think>好的,我现在需要回答用户关于Db2的SELECT COUNT(*)是否会每次都全表扫描的问题。首先,我得回忆一下Db2的机制,特别是查询优化统计信息方面的知识。 用户的问题核心在于是否每次执行COUNT(*)都会触发全表扫描。我知道全表扫描通常是效率较低的,尤其是在大表的情况下。所以,我需要确定Db2有没有优化手段来避免这种情况。 首先,我应该考虑索引的作用。如果表上有合适的索引,Db2可能会选择扫描索引而不是整个表,因为索引通常更小,扫描更。例如,如果有一个非空的B树索引,Db2可能通过扫描索引来获取行数,从而避免全表扫描。但需要确认这一点是否正确,以及是否所有类型的索引都适用。 接下来是统计信息的重要性。Db2的优化器依赖统计信息来决定执行计划。如果统计信息过时,优化器可能会选择全表扫描,即使存在索引。因此,定期更新统计信息可能影响COUNT(*)的执行方式。需要说明统计信息的影响,并建议用户维护最新的统计信息。 然后,是否存在WHERE子句也是一个因素。如果查询包含过滤条件,是否有合适的索引来支持速计数?这时候,索引的使用可能会改变扫描的范围,从而影响是否是全表扫描。用户可能没有考虑到条件查询的情况,所以需要分情况讨论。 另外,表的结构也可能影响结果。比如,如果表是分区表,Db2可能并行扫描各个分区,或者利用分区元数据来加速计数。需要确认分区表是否对COUNT(*)有优化。 还有物化视图的可能性。如果存在预先计算好的物化视图,Db2可能会直接读取物化视图中的计数结果,避免扫描原表。但物化视图的维护成本需要考虑,用户可能没有使用这个功能,但作为潜在优化手段还是需要提及。 此外,可能还有其他因素,比如锁的机制、隔离级别,或者是否启用了某些优化器特性。例如,在某些情况下,Db2可能会使用照隔离来速获取行数,但这可能需要进一步查证。 需要验证一些特殊情况,比如空表的情况。当表为空时,Db2可能直接从系统目录中获取信息,而无需扫描表或索引。系统目录中存储了表的元数据,如行数,但这是否实时更新呢?可能统计信息更新后才会记录,因此如果统计信息不准确,可能导致优化器做出错误决策。 还需要考虑不同版本Db2的行为是否有差异。例如,新版本的Db2可能引入了更优的计数策略,而旧版本可能总是全表扫描。但用户可能没有指定版本,所以需要一般性的回答,同时建议查阅特定版本的文档。 总结可能的优化点:索引扫描代替表扫描、统计信息准确性、分区表优化、物化视图、系统目录的使用。同时,要指出在没有这些优化条件时,确实会发生全表扫描。 然后需要组织这些思考点,以结构化的方式呈现给用户,分点说明影响因素,并给出优化建议。确保语言清晰,避免技术术语过多,同时保持准确性。需要检查是否有错误,比如是否存在索引覆盖所有行的情况,或者某些索引类型是否无法被用于计数。</think>Db2中执行`SELECT COUNT(*)`是否触发全表扫描,取决于**表结构、索引设计、统计信息**等因素。以下是逐步分析: --- ### 1. **无索引或统计信息过期** - **全表扫描**:若表**无可用索引**或优化器认为索引扫描成本更高,Db2会执行全表扫描。 - **统计信息影响**:若统计信息(如`CARD`基数)未更新,优化器可能误判数据量,导致全表扫描。 - **优化建议**: - 定期运行`RUNSTATS`更新统计信息。 - 对大表添加索引(如非空字段的索引)。 --- ### 2. **存在可用索引** - **索引扫描替代全表扫描**: - 若表有**非空字段的索引**,Db2可能选择更小的索引(而非原表)统计行数。 - 例如,若存在索引`CREATE INDEX idx ON table (non_null_column)`,`SELECT COUNT(*)`可能扫描`idx`。 - **限制**: - 若索引未覆盖所有行(如字段允许NULL),仍需回表验证。 --- ### 3. **带WHERE子句的COUNT** - **索引筛选**:若WHERE条件匹配索引,Db2优先使用索引过滤数据。 - 例如:`SELECT COUNT(*) FROM table WHERE indexed_column=1`,可能仅扫描索引。 - **无索引条件**:若无索引支持WHERE条件,仍需全表扫描。 --- ### 4. **分区表的优化** - **并行扫描**:若表为分区表,Db2可能并行扫描各分区,提升速度。 - **元数据加速**:部分场景(如HADR或特定分区策略)可能通过元数据速获取行数。 --- ### 5. **系统目录的缓存值** - **速响应**:`SYSIBM.SYSTABLES`中的`CARD`字段记录了表的行数估计值。 - **注意**:此值为统计信息更新后的近似值,**非实时准确**。若需精确值仍需扫描。 --- ### 总结与建议 | 场景 | 是否全表扫描? | 优化方法 | |------|----------------|----------| | 无索引且统计过期 | 是 | 添加索引 + 更新统计 | | 有非空字段索引 | 否(扫描索引) | 确保索引覆盖所有行 | | WHERE条件匹配索引 | 否(索引筛选) | 创建条件字段索引 | | 分区表 | 可能部分扫描 | 合理设计分区 | --- ### 验证方法 通过`EXPLAIN`工具查看执行计划: ```sql EXPLAIN PLAN FOR SELECT COUNT(*) FROM table; SELECT * FROM TABLE(EXPLAIN_STATEMENT(NULL, NULL, 'BASIC')); ``` 观察`ACCESS_TYPE`字段: - `T`表示全表扫描。 - `I`表示索引扫描。 --- **结论**:Db2的`SELECT COUNT(*)`**不必然全表扫描**,合理设计索引、维护统计信息、利用分区技术均可优化性能。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值