数据库索引选择的探索(二)之直方图

引言

在《数据库索引选择的探索(一)》里,以SYBASE为例讲解现代数据库选择SQL执行计划特别是选择索引的基本原理和过程:SQL执行过程中有多条执行计划多个索引可供选择,数据库查询编译器会采用代价模式根据表的统计信息和直方图计算出代价最小效率最高的执行计划。其中简单的提到了直方图,这次以PostgreSQL数据库为例,深入探讨直方图的由来、作用和查看方法。

直方图的由来

直方图,又叫“质量分布图”。原本是产品生产过程中用来监控预测产品质量情况,反映产品质量分布情况的图表。是根据从生产过程中收集来的质量分布数据,画成以组距为横轴,以出现频数为纵轴一系列连起来的直方型矩形图(柱状图)。其中横轴通常是等宽的连续的范围分段。

在现代数据库系统中,直方图被引入元数据统计信息中,描述表中每列的数据分布。PostgreSQL在2002年发布的7.2版本中引入直方图。

数据库中直方图存在哪里

创建测试表

create t_test_histogram (
n_id int primary key,
c_name varchar(100)
);--为了简化问题将c_id的statistics值设置为10,具体含义下文说明。
alter table t_test_histogram alter c_id set statistics 10;

插入测试数据

            PreparedStatement statement = conn.prepareStatement("insert into t_test_histogram values  (?,?)");for(int i=0;i<100000;i++){if(i<10000){statement.setInt(1, i);statement.setString(2, "test"+i);statement.executeUpdate();}if(i<20000 && i>10000 && i%2==0){statement.setInt(1, i);statement.setString(2, "test"+i);statement.executeUpdate();}if(i<30000 && i>20000 && (i%3==0||i%5==0||i%7==0) ){statement.setInt(1, i);statement.setString(2, "test"+i);statement.executeUpdate();}if(i<40000 && i>30000 &&  (i%3==0||i%5==0) ){statement.setInt(1, i);statement.setString(2, "test"+i);statement.executeUpdate();}if(i<50000 && i>40000  && i%3==0){statement.setInt(1, i);statement.setString(2, "test"+i);statement.executeUpdate();}if(i<60000 && i>50000  && (i%3==0 && i%5==0)){statement.setInt(1, i);statement.setString(2, "test"+i);statement.executeUpdate();}if(i > 60000  && (i%3==0 && i%5==0 && i%7==0)){statement.setInt(1, i);statement.setString(2, "test"+i);statement.executeUpdate();}

查看直方图

在ABase数据库中,直方图信息存储在pg_statistic表中,通常通过其视图pg_stats来查看。
查看表”t_test_histogram”的”n_id”列的直方图的SQL如下:

SQL1:

abase=# select tablename,attname,histogram_bounds from pg_stats where tablename = 't_test_histogram' and attname = 'n_id';

结果1:

tablename attname histogram_bounds
t_test_histogram n_id {0,2947,5894,8841,13578,19472,24942,30438,36753,44295,99960}

- 查询结果含义:
histogram_bounds列结果是将n_id的分布情况分成了10组(桶),每组占总数量的比例是相同的,即1/10。
即:

序号 n_id取值范围 数据占比
1 0至2947 0.1
2 2947至5894 0.1
3 5894至8841 0.1
4 8841至13578 0.1
5 13578至19472 0.1
6 19472至24942 0.1
7 24942至30438 0.1
8 30438至36753 0.1
9 36753至44295 0.1
10 44295至99960 0.1
  • 其他范围数据分布怎么计算?

直方图假设每个组(桶)内的数据是按照线性分布(平均分布),跨组的数据占比为所跨组的总占比加该数据范围在组内的占比

n_id中10至100范围数据占比
P(10,100) = (100-10)/(2947-0)*0.1
= 0.0030539

n_id中100至40000范围数据占比
P(100,6000)= (2947-100)/(2947-0)*0.1 +0.1*7+(40000-36753)/(44295-36753)*0.1
=0.0966067187+0.7+0.0430522408
=0.8396589

数据库如何使用直方图

  • 数据库根据计算出来的数据范围占比(选择度),进行代价估算中行数估算。

如SQL2:

select * from t_test_histogram where n_id > 100 and n_id <40000

第一步:根据pg_class得出t_test_histogram共有多少行

abase=# select reltuples from pg_class where relname = 't_test_histogram';reltuples
-----------29472
(1 row)

第二步:根据100至40000的数据占比估算出where n_id > 100 and n_id <40000 的行数

rows = P(100,6000) * reltuples = 0.8396589*29472 = 24746

最后:验证结果,执行计划估算的rows值等于直方图估算的rows值。

abase=# explain select * from t_test_histogram where n_id > 100 and n_id <40000;
                              QUERY PLAN
-----------------------------------------------------------------------
 Seq Scan on t_test_histogram  (cost=0.00..769.08 rows=24746 width=13)
   Filter: ((n_id > 100) AND (n_id < 40000))
(2 rows)

更复杂的直方图计算

t_test_histogram例子中我们只演示计算了n_id的数据占比的情况,n_id是主键(唯一索引也类似)不涉及重复值和等值计算的问题(每个值出现的频率是一样的,P=1/reltuples)

  • 等值的范围占比(where c_name = ‘xxx’)是怎么计算的呢?

等值计算是通过pg_stats 中的常用值和常用值出现频率计算的,不是通过直方图计算的。

  • 普通列(非主键或唯一索引)的不等值占比范围(where c_name < ‘xxx’)是怎么计算的呢?

是结合计算出等值的占比范围和直方图占比范围共同计算出来的

直方图可能造成的问题

  • 各种原因(关闭定时更新统计值或没有定时更新)造成的统计信息不及时准确,会造成数据范围占比估算错误

例如:
删掉n_id < 39999的行。

abase=# delete from t_test_histogram where n_id < 39999;
DELETE 25091

查看直方图信息

abase=# select tablename,attname,histogram_bounds from pg_stats where tablename = 't_test_histogram' and attname = 'n_id';
    tablename     | attname |                       histogram_bounds
------------------+---------+--------------------------------------------------------------
 t_test_histogram | n_id    | {0,2947,5894,8841,13578,19472,24942,30438,36753,44295,99960}
(1 row)

查看行占比范围估算

abase=# explain select * from t_test_histogram where n_id > 100 and n_id <40000;
                              QUERY PLAN
-----------------------------------------------------------------------
 Seq Scan on t_test_histogram  (cost=0.00..769.08 rows=24846 width=13)
   Filter: ((n_id > 100) AND (n_id < 40000))
(2 rows)

此处的行范围估算是错误

更新统计值后,再看直方图和行估算

abase=# analyze t_test_histogram;
ANALYZEabase=# select tablename,attname,histogram_bounds from pg_stats where tablename = 't_test_histogram' and attname = 'n_id';
    tablename     | attname |                          histogram_bounds
------------------+---------+---------------------------------------------------------------------
 t_test_histogram | n_id    | {39999,41313,42627,43941,45255,46569,47883,49197,52560,59130,99960}
(1 row)abase=# explain select * from t_test_histogram where n_id > 100 and n_id <40000;
                                          QUERY PLAN
-----------------------------------------------------------------------------------------------
 Index Scan using t_test_histogram_pkey on t_test_histogram  (cost=0.28..8.30 rows=1 width=14)
   Index Cond: ((n_id > 100) AND (n_id < 40000))
(2 rows)
  • 采样组(桶)太少,导致直方图不能精确反馈数据分布的变化

总结

  • 直方图信息存储在pg_statistics 中,通常通过pg_stats查看
  • 直方图是用来表述表中列数据分布的,数据库通过直方图可以计算出where条件中列的占比范围(选择度)
  • 不准确的直方图信息会造成选择度计算不准确,进而导致数据占比范围代价估算不准确。
  • 造成代价估算不准的原因是分析不及时和统计采样值太少

反思

排查SQL问题的同事经常会遇到这么一个情况,”公司环境的慢SQL在生产环境不慢,生产环境的慢SQL在公司不慢”,造成这个问题的重要原因是我们加压数据分布的还不够准确,不能够真实的模拟生产环境的数据。通过对直方图原理的了解,我们可以利用直方图改进我们的加压工具,在公司模拟出更真实的加压数据环境,提早发现问题,提高产品质量。

数据库索引选择的探索(二)之直方图相关推荐

  1. 为什么MySQL数据库索引选择使用B+树?

    在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择使 ...

  2. 数据库索引原理讲解之二

    本文转自:http://www.cnblogs.com/c-gis/archive/2012/07/27/2612175.html 和 http://blog.csdn.net/coolzyt/art ...

  3. mysql性能结构优化原理_MySQL性能管理及架构设计(二):数据库结构优化、高可用架构设计、数据库索引优化...

    一.数据库结构优化(非常重要) 1.1 数据库结构优化目的 1.减少数据冗余:(数据冗余是指在数据库中存在相同的数据,或者某些数据可以由其他数据计算得到),注意,尽量减少不代表完全避免数据冗余: 2. ...

  4. ef mysql 优化_MySQL性能管理及架构设计(二):数据库结构优化、高可用架构设计、数据库索引优化...

    一.数据库结构优化(非常重要) 1.1 数据库结构优化目的 1.减少数据冗余:(数据冗余是指在数据库中存在相同的数据,或者某些数据可以由其他数据计算得到),注意,尽量减少不代表完全避免数据冗余: 2. ...

  5. MySQL性能管理及架构设计(二):数据库结构优化、高可用架构设计、数据库索引优化...

    一.数据库结构优化(非常重要) 1.1 数据库结构优化目的 1.减少数据冗余:(数据冗余是指在数据库中存在相同的数据,或者某些数据可以由其他数据计算得到),注意,尽量减少不代表完全避免数据冗余: 2. ...

  6. mysql进阶(二十七)数据库索引原理

    文章目录 一.前言 二.数据结构及算法理论 2.1 B+树 2.2 二叉查找树 2.3 AVL树 2.4 B+树的特性 三.聚集索引.非聚集索引 3.1 聚集索引 3.2 非聚集索引 一.前言 本文主 ...

  7. 大于小于优化_以MySQL为例,详解数据库索引原理及深度优化

    本文内容主要来源于互联网上主流文章,只是按照个人理解稍作整合,后面附有参考链接. 一.摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引 ...

  8. 什么是m叉树_不懂数据库索引的底层原理?那是因为你心里没点b树

    点击上方"后端技术精选",选择"置顶公众号" 技术文章第一时间送达! 作者:苏苏喂 cnblogs.com/sujing/p/11110292.html 题外话 ...

  9. mysql 节点查根_(三)B数、B+树及在数据库索引中应用

    在算法逻辑上,二叉树的查找效率和比较次数都是最小的,但是在实际问题中,还要考虑磁盘IO. 数据库索引是存储在磁盘上的,当数据量比较大时,索引可能几个G. 当我们利用索引查询的时候,不能将整个索引全部加 ...

  10. B-树和B+树的应用:数据搜索和数据库索引

    http://blog.csdn.net/hguisu/article/details/7786014 http://blog.csdn.net/xlgen157387/article/details ...

最新文章

  1. gearman mysql udf
  2. java分解因式_用JAVA因式分解 并以9=3×3格式输出
  3. 引导扇区维护工具linux,BOOTICE(引导扇区维护工具)
  4. c# 编程学习(二)
  5. 爱卡创誓记java饰品,《创誓记AIKA》芙兰精灵配上框架眼睛折服宅男宅女
  6. react入门(一)
  7. 谈谈R中的乱码(二)
  8. Go语言学习之旅--初识GoLang
  9. 谷歌浏览器无法登陆禅道问题
  10. 【电子发票】电子发票OFD如何打开?OFD版式阅读器
  11. [转]Android 上百实例源码分析以及开源分析
  12. horner算法matlab实现,使用Euclid和Horner算法的多项式求值
  13. 【锐捷】交换机,AC设备虚拟化(VSU、VAC)
  14. 《自控力》-- 精华摘抄
  15. win7计算机管理无用户账户,win7系统控制面板中用户账户显示空白的解决方法
  16. body中的相关标签
  17. bzoj1754: [Usaco2005 qua]Bull Math
  18. 小学第三册上计算机wps教案,《初始WPS》教学设计——溧阳市横涧小学  夏春芳...
  19. ros dwa局部路径规划原理
  20. vue集成codemirror代码编辑器

热门文章

  1. jar中没有主清单属性
  2. png图片转换jpg,保姆级教程一学就会
  3. 高大上的cmd命令行来袭!颜值与内涵兼备
  4. 微信小程序制作FC模拟器,从入坑到放弃
  5. python同步油管用户信息
  6. OpenG 分化基础知识
  7. c语言中isupper用法,C 库函数 - isupper()
  8. 黑苹果后遗症 台式机Win10时间总是不同步
  9. Python面向对象加强4.iter与next的用法,枚举器enumerate
  10. Word重复操作快捷键F4