暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL8.0 Optimizer Statistics

扫地僧的故事 2020-07-07
1112
今天大家都赚钱了吗?😁

MySQL8.0之前的版本中,只有简单的统计信息,并没有提供统计直方图(如果熟悉Oracle的小伙伴,肯定知道那个让我们有又爱又恨的统计直方图了)。8.0的版本中,MySQL实现了这个功能,通过column_statistics这个数据字典存储列的直方图信息,供优化器生成查询执行计划的使用。个人认为,由于MySQL的一些特性,在MySQL中,好处远远多于坏处。我们可以用ANALYZE TABLE语句对直方图进行管理。

column_statistics的特征:

  • 该表包含除空间数据和JSON之外的所有数据类型的列的统计信息。

  • 该表是持久化的,因此不必在每次服务器启动时创建列统计信息。

  • MySQL会对这张表执行更新. 用户没有办法用update语句修改。

column_statistics表是不能被用户直接访问的,因为它是数据字典的一部分。但是查看直方图信息,我们可以使用INFORMATION_SCHEMA.COLUMN_STATISTICS,它作为数据字典表上的一个视图实现。COLUMN_STATISTICS有以下几列:

  • SCHEMA_NAME, TABLE_NAME,COLUMN_NAME:这个看名字就知道没必要多说。

  • HISTOGRAM: 是一个JSON值, 以直方图的方式描述列统计信息。

列直方图包含存储在列中的值范围的部分bucket。直方图是JSON对象,可以灵活地表示列统计信息。例如,

    CREATE TABLE `t_histograms` (
     `id` int NOT NULL,
     `c1` int DEFAULT NULL,
     `c2` varchar(10) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

    复制

      --收集列c1直方图统计信息

      analyze table t_histograms UPDATE HISTOGRAM on c1;

      --查看C1(int)直方图
      select json_pretty(histogram) from
      INFORMATION_SCHEMA.COLUMN_STATISTICS where schema_name='test' and table_name='t_histograms' and column_name='c1';
      {
       "buckets": [
         [
           1,
           0.6
      ],
         [
           2,
           0.8
      ],
         [
           3,
           1.0
      ]
       ],
       "data-type": "int",
       "null-values": 0.0,
       "collation-id": 8,
       "last-updated": "2020-07-05 10:57:03.429238",
       "sampling-rate": 1.0,
       "histogram-type": "singleton",
       "number-of-buckets-specified": 100

      }

      复制

        --收集列c2直方图统计信息
        analyze table t_histograms UPDATE HISTOGRAM on c2;
        --查看C2(字符串)直方图
        select json_pretty(histogram) from INFORMATION_SCHEMA.COLUMN_STATISTICS where schema_name='test' and table_name='t_histograms' and column_name='c2';
        {
        ...
           [
             4800,
             4849,
             0.96999399879976,
             50
        ],
           [
             4850,
             4899,
             0.9799959991998399,
             50
        ],
           [
             4900,
             4949,
             0.98999799959992,
             50
        ],
           [
             4950,
             4999,
             1.0,
             50
        ]
         ],
         "data-type": "int",
         "null-values": 0.0,
         "collation-id": 8,
         "last-updated": "2020-07-05 15:07:24.070861",
         "sampling-rate": 1.0,
         "histogram-type": "equi-height",
         "number-of-buckets-specified": 100
        }



        复制


        无法在主键或唯一键上收集统计直方图!

          analyze table tt1 update histogram on c1;
          +----------+-----------+----------+-----------------------------------------------------------+
          | Table    | Op        | Msg_type | Msg_text                                                  |
          +----------+-----------+----------+-----------------------------------------------------------+
          | test.tt1 | histogram | Error    | The column 'c1' is covered by a single-part unique index. |
          +----------+-----------+----------+-----------------------------------------------------------+

          复制


          直方图的Key

          *****Buckets:直方图bucket

          1、对于singleton直方图,包括两个值:

          • Value 1: bucket的值, 取决于列的数据类型及数据

          • Value 2: 表示该值的累积频率(double类型). 例如{2,0.8}表示80%的值小于等于2,2的值占20%


          2、对于equi-height(等高)直方图, 包含以下四个值:

          • Value 1,2 : bucket中的最大值和最小值

          • Value 3: 表示该值的累积频率(double类型)

          • Value 4: 在这个bucket中列值的num_distinct(不同的值有几个)


          ***** null-values: 取值范围0.0-1.0 列值中null值所占的比例。

          ***** last-updated: 直方生成的时间。

          ***** sample-rate: 收集时的采样比。

          ***** histogram-type:

          1、 Singleton:  频度直方图.当列的NDV小于analyze table … with N buckets指定的桶数时, 一个直方图表示一个值的占比. N 默认为100。

          2.、Equi-height: 等高直方图.当列的NDV超过analyze table时指定的桶数时, 只能用等高直方图表示了。


          ***** number-of-buckets-specified: 指定的直方图bucket数,默认为100。

          ***** data-type: 列的数据类型。int,double,decimal,datetime,string…

          ***** collation-id: 直方图数据的校对ID。当数据类型值为string时,它最有意义。值对应于INFORMATION_SCHEMA中的ID列值。


          优化器应用直方图统计信息,根据列值与常数值比较的选择性(过滤效果)来确定行估计值。这些谓词表格符合直方图使用:

          col_name = constant 

          col_name <> constant 

          col_name != constant 

          col_name > constant 

          col_name < constant 

          col_name >= constant 

          col_name <= constant 

          col_name IS NULL 

          col_name IS NOT NULL 

          col_name BETWEEN constant AND constant 

          col_name NOT BETWEEN constant AND constant 

          col_name IN (constant[, constant] ...) 

          col_name NOT IN (constant[, constant] ...) 




          案例

          Sample1:

            mysql> select table_rows from information_schema.tables where table_name='tt3';
            +------------+
            | TABLE_ROWS |
            +------------+
            |          5 |
            +------------+




            mysql> select json_pretty(histogram) from  information_schema.column_statistics where table_name='tt3' and column_name='c1';
            ...
            {
             "buckets": [
               [
             1,
                 0.6
            ],
               [
             2,
                 0.8
            ],
               [
                 3,
                 1.0
            ]
             ],
             "data-type": "int",
             "null-values": 0.0,
             "collation-id": 8,
             "last-updated": "2020-07-05 16:37:08.023031",
             "sampling-rate": 1.0,
             "histogram-type": "singleton",
             "number-of-buckets-specified": 100
            }

            复制

            从上面的直方图信息,可以看到

            如果 c1=2选择率为20%, 选择率*总行数=预估行数,应该为1行。

            如果 c1=1选择率为60%,选择率*总行数=预估行数,应该为3行。


            Sample2(等高直方图):

              mysql> select json_pretty(histogram) from information_schema.column_statistics where table_name='bigtable' and column_name='c2';

                [
                   "base64:type254:MDAwMDAwMDAwMDAwMDAwOTc4MDk=",
                   "base64:type254:MDAwMDAwMDAwMDAwMDAwOTg1Mzg=",
                   0.9799942488600419,
                   993
              ],
                 [
                   "base64:type254:MDAwMDAwMDAwMDAwMDAwOTg1Mzk=",  
                   "base64:type254:MDAwMDAwMDAwMDAwMDAwOTkyNjk=",
                   0.9900039710252092,
                   994
              ],
                 [
                   "base64:type254:MDAwMDAwMDAwMDAwMDAwOTkyNzA=",
                   "base64:type254:MDAwMDAwMDAwMDAwMDAwOTk5OTk=",
                   1.0,
                   993
              ]
               ],
               "data-type": "string",
               "null-values": 0.0,
               "collation-id": 255,
               "last-updated": "2020-07-06 06:01:04.501517",
               "sampling-rate": 0.7353382379413353,
               "histogram-type": "equi-height",
               "number-of-buckets-specified": 100
              }


              mysql> select from_base64('MDAwMDAwMDAwMDAwMDAwOTg1Mzk=');
              +------------------------------------------------------------------------------------------+
              | from_base64('MDAwMDAwMDAwMDAwMDAwOTg1Mzk=')                                              |
              +------------------------------------------------------------------------------------------+
              | 0x3030303030303030303030303030303938353339                                               |
              +------------------------------------------------------------------------------------------+
              1 row in set (0.00 sec)


              mysql> select * from bigtable where c2=0x3030303030303030303030303030303938353339;
              +-------+------+----------------------+---------------------+
              | id    | c1   | c2                   | d1                  |
              +-------+------+----------------------+---------------------+
              | 98539 |    1 | 00000000000000098539 | 2020-07-06 05:46:20 |
              +-------+------+----------------------+---------------------+
              1 row in set (0.05 sec)

              复制

                我们以c2>'00000000000000098539' 为例,
                [  
                  "base64:type254:MDAwMDAwMDAwMDAwMDAwOTg1Mzk=",  <<===00000000000000098539  
                  "base64:type254:MDAwMDAwMDAwMDAwMDAwOTkyNjk=",  <<===00000000000000099269  
                  0.9900039710252092,  
                 994  
                ]  



                复制

                "c2>'00000000000000098539'" 这个条件选择率为:

                (1 - 0.9900039710252092) +(0.9900039710252092 - 0.9799942488600419) =  0.0200057511399581=2%  


                总结:

                网上很多人都说统计直方图这个功能很鸡肋,需要手动来建立更新,并且单纯的使用直方图对数据的查询帮助有限,但是正确的估算选择率与Cardinality对查询的访问路径及连接方式有至关重要的作用。MySQL 从8.0开始已经不再仅仅是互联网类的数据库,正在往全方位,企业级的数据迈进,期待以后的功能越做越好~


                今天很正经,没有美女图🙈,只有单纯的技术分享,以上仅是我个人的学习分享,如有哪里理解得不对,欢迎大家指出,谢谢~




                    





                文章转载自扫地僧的故事,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论