关于大表查询的性能瓶颈

在 OceanBase(MySQL 模式下),我有一张几个亿记录的大表,执行简单的 SELECT MIN(id) 或 SELECT MAX(id) 查询时,耗时非常长(将近10秒),而在同样配置的 Oracle 中只需要几百毫秒。从数据库内核的角度看,造成这种性能差异的可能原因是什么?除了调整超时时间,有没有更好的实践来优化这类聚合查询?

6 个赞

期待答复

1 个赞

把表改为分区表,建分区索引,加并行度等等,我是这么考虑的

2 个赞

试一下列存表效果如何

1 个赞

是否涉及分布式查询呢?

1 个赞

@论坛小助手

1 个赞

在 OceanBase 数据库中,大表的简单聚合查询性能较差的原因可能与执行计划的选择有关。具体来说,如果查询没有使用索引而选择了全表扫描,会导致大量的逻辑读取,显著增加查询时间。此外,优化器的统计信息不准确也可能导致执行计划选择不优。为了优化这类查询,您可以采取以下措施:

  1. 确保索引存在:检查表上的 id 列是否有合适的索引。如果 id 列是主键或有唯一索引,通常会使用索引进行聚合查询。
  2. 收集统计信息:确保表的统计信息是最新的。可以使用 DBMS_STATS 包来收集统计信息,例如:
    CALL DBMS_STATS.GATHER_TABLE_STATS('your_schema', 'your_table');
    
  3. 使用 Hint 强制索引:如果优化器没有选择最优的索引,可以使用 Hint 强制使用索引。例如:
    SELECT /*+ INDEX(your_table your_index) */ MIN(id) FROM your_table;
    
  4. 检查执行计划:使用 EXPLAIN 语句查看查询的执行计划,确保查询使用了索引而不是全表扫描。例如:
    EXPLAIN SELECT MIN(id) FROM your_table;
    
  5. 优化表结构:如果表的结构设计不合理,可能需要重新设计表结构,例如使用分区表来减少查询的数据量。
  6. 配置参数:确保数据库的配置参数适合大表查询,例如调整 ob_query_timeout 以防止查询因超时而中断。
    通过以上措施,可以显著提升大表聚合查询的性能。

检索到的文档如下:

  1. SQL 性能问题的典型场景和排查思路
  2. SQL 调优典型场景和案例
  3. OceanBase 数据库性能的影响因素
  4. 如何获取表的直方图
  5. 常见的 SQL 调优方式
  6. 手动收集统计信息
1 个赞

对统计字段加索引啊.

用列存,向量化+SIMD(相当于批处理,你可以理解行存是一行行处理,串着的),而且列存压缩率,以及 所需的数据可能更集中(实际看你SQL怎么写的,例如只查单列,条件也只有这一列,那么相比于行存 IO会大大减少),列存还会在宏块/微块中 提前计算 min、max 这种聚合信息,这样只需要取这些聚合信息,而不需要重新对比(减少CPU计算),然后用败者树,做个最大/最小堆,这事就完成了,如果再采用 MOW 的方式,在增量数据库记录完整的行,那么部分算子可以分别 下推到 增量和基准数据(提前筛选所需数据,而不是增量和基准数据合并后,再计算,可以极大减少计算量)。

总结下上面用到的方法:

  1. 让所需的数据集中,节省IO(列存);
  2. 让单核CPU并行,提高单核cpu计算能力(向量化+SIMD);
  3. 提前计算(列存会提前计算一些 聚合类的数值,如:max、min等);
  4. 算子下推(MOW);

Oracle 的话,是堆表,我估计用到了3 (I guess)。