MySQL直方图统计信息使用场景

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 当需要过滤的字段上既没有索引也没有直方图时,优化器会根据MySQL代码中内置的默认规则估计过滤的比率,实际很大程度上是瞎猜,部分常用的默认规则如下

当需要过滤的字段上既没有索引也没有直方图时,优化器会根据MySQL代码中内置的默认规则估计过滤的比率,实际很大程度上是瞎猜,部分常用的默认规则如下:

过滤类型

过滤比率%

=

10

<>或≠

90

< 或 >

33.33

between

11.11

in

字段数×1050的最小值

下面是SQL语句的执行计划中默认过滤比率的几个例子首先设置pager使执行计划只显示过滤比率



mysql> pager grep filteredPAGER set to 'grep filtered'

等于检索字段的默认过滤比率为10%




mysql> explain select * from actor where first_name='lisa'\G     filtered: 10.001 row in set, 1 warning (0.00 sec)

大于或小于检索字段的默认过滤比率为三分之一




mysql> explain select * from actor where first_name>'lisa'\G     filtered: 33.331 row in set, 1 warning (0.00 sec)

不等于检索字段的默认过滤比率为90%




mysql> explain select * from actor where first_name<>'lisa'\G     filtered: 90.001 row in set, 1 warning (0.00 sec)

between的默认过滤比率为11.11%:




mysql> explain select * from actor where last_update between '2006-02-15' and '2006-02-16'\G     filtered: 11.111 row in set, 1 warning (0.00 sec)

下面SQL中in的过滤比率为20%




mysql> explain select * from actor where first_name in ('lisa','THORA')\G     filtered: 20.001 row in set, 1 warning (0.00 sec)

使用默认规则估计过滤比率往往是不准的,因此很多时候会生成错误的执行计划,这个时候在字段上收集直方图统计信息可以解决这个问题。而且直方图即使不用于改变SQL语句的执行计划,也可以用于在执行计划中的filt列显示正确的过滤的比例。

编写一个简单的SQL语句,查询在payment表里面支付的金额大于10元的客户号,生成这个SQL的执行计划如下
















mysql> explain select customer_id from payment where amount>10\G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: payment   partitions: NULL         type: ALLpossible_keys: NULL          key: NULL      key_len: NULL          ref: NULL         rows: 16086     filtered: 33.33        Extra: Using where1 row in set, 1 warning (0.00 sec)

判断amount字段大于10的记录,由于这个字段上没有直方图的统计信息,优化器根据代码中内置的默认值估计有三分之一的记录属于这个范围。再判断amount大于100的记录的执行计划如下
















mysql> explain select customer_id from payment where amount>100\G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: payment   partitions: NULL         type: ALLpossible_keys: NULL          key: NULL      key_len: NULL          ref: NULL         rows: 16086     filtered: 33.33        Extra: Using where1 row in set, 1 warning (0.00 sec)

优化器仍然估计有三分之一的记录属于这个范围,显然优化器在瞎猜为了解决这个问题,现在在amount字段上创建直方图的统计信息的命令和输出结果如下








mysql> analyze table payment update histogram on amount with 256 buckets\G*************************** 1. row ***************************   Table: sakila.payment      Op: histogramMsg_type: statusMsg_text: Histogram statistics created for column 'amount'.1 row in set (0.31 sec)

再重新生成这个SQL语句的执行计划如下
















mysql> explain select customer_id from payment where amount>10\G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: payment   partitions: NULL         type: ALLpossible_keys: NULL          key: NULL      key_len: NULL          ref: NULL         rows: 16086     filtered: 0.71        Extra: Using where1 row in set, 1 warning (0.00 sec)

优化器根据直方图的统计信息估计符合这个条件的记录只占总数0.71%

删除这个直方图的命令如下








mysql> analyze table payment drop histogram on amount\G*************************** 1. row ***************************   Table: sakila.payment      Op: histogramMsg_type: statusMsg_text: Histogram statistics removed for column 'amount'.1 row in set (0.01 sec)

下面的SQL语句查询单词消费金额大于10元和在第一个店进行消费的顾客的姓名,在没有直方图时的生成的执行计划如下:









mysql> explain analyze select first_name,last_name from customer inner join payment using (customer_id) where  amount>10 and store_id=1\G*************************** 1. row ***************************EXPLAIN: -> Nested loop inner join  (cost=3100.48 rows=2918) (actual time=0.443..14.853 rows=68 loops=1)    -> Index lookup on customer using idx_fk_store_id (store_id=1)  (cost=36.35 rows=326) (actual time=0.310..0.707 rows=326 loops=1)    -> Filter: (payment.amount > 10.00)  (cost=6.72 rows=9) (actual time=0.042..0.043 rows=0 loops=326)        -> Index lookup on payment using idx_fk_customer_id (customer_id=customer.customer_id)  (cost=6.72 rows=27) (actual time=0.031..0.038 rows=27 loops=326) 1 row in set (0.01 sec)

可以看到优化器先对符合在第一个店进行消费的条件进行过滤,然后再过滤消费金额大于10元的条件。在字段amount上有直方图统计信息之后,再次生成这个SQL语句的执行计划如下








mysql> explain analyze select first_name,last_name from customer inner join payment using (customer_id) where  amount>10 and store_id=1\G
*************************** 1. row ***************************
EXPLAIN: -> Nested loop inner join  (cost=1672.84 rows=62) (actual time=0.328..9.507 rows=68 loops=1)
    -> Filter: (payment.amount > 10.00)  (cost=1632.85 rows=114) (actual time=0.224..8.421 rows=114 loops=1)
        -> Table scan on payment  (cost=1632.85 rows=16086) (actual time=0.191..6.482 rows=16049 loops=1)
    -> Filter: (customer.store_id = 1)  (cost=0.25 rows=1) (actual time=0.009..0.009 rows=1 loops=114)
        -> Single-row index lookup on customer using PRIMARY (customer_id=payment.customer_id)  (cost=0.25 rows=1) (actual time=0.009..0.009 rows=1 loops=114)
1 row in set (0.02 sec)

可以看到优化器将这两个过滤条件的先后次序反转过来了,因为借助直方图统计信息,优化器知道消费金额大于10元这个条件的选择性更高。从估计成本和实际执行时间都可以看出,有直方图的执行计划效率要好很多!直方图在某些场景下可以帮助优化器生成更优的执行计划,那么在什么样的字段上考虑使用直方图呢,这里建议符合下面4个条件字段可以考虑建立直方图统计信息:

(1)值分布不均匀,优化器很难估计值的分布的字段。

(2)选择性差的字段,否则索引更适合。

(3)用于where子句中过滤的字段或用于连接的字段。

(4)字段值分布规律不随时间变化的字段。因为直方图统计信息不会自动收集,如果字段值分布规律发生大的变化,统计信息会失真。

实际工作中,可以使用explain analyze分析SQL语句的执行计划,如果估算的rows和实际的rows相差过大,可以考虑在过滤字段上创建直方图统计信息。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
存储 SQL 关系型数据库
轻松入门MySQL:加速进销存!利用MySQL存储过程轻松优化每日销售统计(15)
轻松入门MySQL:加速进销存!利用MySQL存储过程轻松优化每日销售统计(15)
167 0
|
2月前
|
关系型数据库 MySQL
MySQL查看连接数和进程信息
这篇文章介绍了如何在MySQL中查看连接数和进程信息,包括当前打开的连接数量、历史成功建立连接的次数、连接错误次数、连接超时设置,以及如何查看和终止正在执行的连接进程。
550 10
|
1月前
|
存储 SQL 关系型数据库
MySQL 存储过程错误信息不打印在控制台
MySQL 存储过程错误信息不打印在控制台
60 1
|
1月前
|
存储 关系型数据库 MySQL
MySQL 如何存储地理信息
MySQL 如何存储地理信息
96 1
|
1月前
|
SQL 存储 关系型数据库
mysql 数据库空间统计sql
mysql 数据库空间统计sql
45 0
|
6月前
|
Cloud Native 关系型数据库 MySQL
云原生数据仓库产品使用合集之ADB MySQL湖仓版和 StarRocks 的使用场景区别,或者 ADB 对比 StarRocks 的优劣势
阿里云AnalyticDB提供了全面的数据导入、查询分析、数据管理、运维监控等功能,并通过扩展功能支持与AI平台集成、跨地域复制与联邦查询等高级应用场景,为企业构建实时、高效、可扩展的数据仓库解决方案。以下是对AnalyticDB产品使用合集的概述,包括数据导入、查询分析、数据管理、运维监控、扩展功能等方面。
|
4月前
|
DataWorks 监控 关系型数据库
利用 DataWorks 数据推送定期推播 MySQL 或 StarRocks Query 诊断信息
DataWorks 近期上线了数据推送功能,能够将数据库查询的数据组织后推送到各渠道 (如钉钉、飞书、企业微信及 Teams),除了能将业务数据组织后推送,也能将数据库自身提供的监控数据组织后推送,这边我们就以 MySQL (也适用于StarRocks) 为例,定期推播 MySQL 的数据量变化等信息,帮助用户掌握 MySQL 状态。
106 1
|
4月前
|
XML Java 关系型数据库
Action:Consider the following: If you want an embedde ,springBoot配置数据库,补全springBoot的xml和mysql配置信息就好了
Action:Consider the following: If you want an embedde ,springBoot配置数据库,补全springBoot的xml和mysql配置信息就好了
|
4月前
|
SQL 数据库 关系型数据库
MySQL设计规约问题之为什么统计表中记录数时推荐使用COUNT(*)而不是COUNT(primary_key)或COUNT(1)
MySQL设计规约问题之为什么统计表中记录数时推荐使用COUNT(*)而不是COUNT(primary_key)或COUNT(1)
|
4月前
|
存储 SQL 关系型数据库
MySQL设计规约问题之存储状态、性别等信息时,应该使用哪种数据类型
MySQL设计规约问题之存储状态、性别等信息时,应该使用哪种数据类型