MySQL统计信息不准导致的性能问题

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 统计信息不准导致错误的执行计划,引发性能问题

表的统计信息错误导致优化器选择错误的执行计划。

一个客户的性能优化案例: 没有修改数据库实例的任何配置参数以及业务代码没有变更的情况下,一条 sql 出现大幅性能下降。

我们来看看出问题的sql 以及他的执行计划:

mysql> explain 
-> SELECT count(con.id)          ,
->        MAX(DAYNAME(con.date)) ,
->        now()                  ,
->        pcz.type,
->        pcz.c_c
-> FROM   con AS con
->        join orders o on con.o_id = o.id
->        JOIN pcz AS pcz ON o.d_p_c_z_id = pcz.id
->        left join c c on con.c_id = c.id
-> WHERE con.date = current_date() and pcz.type = "T_D"
-> GROUP BY con.date, pcz.c_c,  pcz.type;
+----+-------------+-------+------------+--------+-------------------+----------+---------+----------------------------+------+----------+----------------------------------------------+
| id | select_type | table | partitions | type   | possible_keys     | key      | key_len | ref                        | rows | filtered | Extra                                        |
+----+-------------+-------+------------+--------+-------------------+----------+---------+----------------------------+------+----------+----------------------------------------------+
|  1 | SIMPLE      | pcz   | NULL       | ALL    | PRIMARY           | NULL     | NULL    | NULL                       |  194 |    10.00 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | o     | NULL       | ref    | PRIMARY,dpcz_FK   | dpcz_FK  | 9       | custom.pcz.id              | 1642 |   100.00 | Using index                                  |
|  1 | SIMPLE      | con   | NULL       | ref    | FK_order,IDX_date | FK_order | 8       | custom.o.id                |    1 |     4.23 | Using where                                  |
|  1 | SIMPLE      | c     | NULL       | eq_ref | PRIMARY           | PRIMARY  | 8       | custom.con.c_id            |    1 |   100.00 | Using index                                  |
+----+-------------+-------+------------+--------+-------------------+----------+---------+----------------------------+------+----------+----------------------------------------------+

执行计划显示 rows  examined = (19410%)1642(14.23%)=1347 查看执行计划我们就发现 where 条件 con.date = current_date() 。这个条件看起来更适合作为索引过滤数据。但是 为什么 MySQL 优化器不选择该索引呢?接下来使用 force index 强制执行计划使用 con.date 字段上的索引。执行计划如下:

mysql> explain 
-> SELECT count(con.id)          ,
->        MAX(DAYNAME(con.date)) ,
->        now()                  ,
->        pcz.type,
->        pcz.c_c
-> FROM   con AS con USE INDEX(IDX_date)
->        join orders o on con.o_id = o.id
->        JOIN p_c_z AS pcz ON o.d_p_c_z_id = pcz.id
->        left join c c on con.c_id = c.id
-> WHERE con.date = current_date() and pcz.type = "T_D"
-> GROUP BY con.date, pcz.c_c,  pcz.type;
+----+-------------+-------+------------+--------+-----------------+----------+---------+---------------------------------------+--------+----------+---------------------------------+
| id | select_type | table | partitions | type   | possible_keys   | key      | key_len | ref                                   | rows   | filtered | Extra                           |
+----+-------------+-------+------------+--------+-----------------+----------+---------+---------------------------------------+--------+----------+---------------------------------+
|  1 | SIMPLE      | con   | NULL       | ref    | IDX_date        | IDX_date | 3       | const                                 | 110446 |   100.00 | Using temporary; Using filesort |
|  1 | SIMPLE      | c     | NULL       | eq_ref | PRIMARY         | PRIMARY  | 8       | custom.con.c_id                       |      1 |   100.00 | Using index                     |
|  1 | SIMPLE      | o     | NULL       | eq_ref | PRIMARY,dpcz_FK | PRIMARY  | 8       | custom.con.o_id                       |      1 |   100.00 | Using where                     |
|  1 | SIMPLE      | pcz   | NULL       | eq_ref | PRIMARY         | PRIMARY  | 8       | custom.o.d_p_c_z_id                   |      1 |    10.00 | Using where                     |
+----+-------------+-------+------------+--------+-----------------+----------+---------+---------------------------------------+--------+----------+---------------------------------+

问题来了  rows examined = 110446*(1*10%)=11045 rows根据计算评估, 第一个执行计划的 1347 大概是 110446 的十分之一 ,至少从表面上看来这个是MySQL 优化器选择第一个执行计划的原因。

但是对比实际的查询结果的响应时间,肯定粗问题了。因为执行计划二 的sql 的响应时间在预期之内,但是执行计划一对应的响应时间反而更慢。

进一步来看表 orders 的创建语句以及执行计划1,我们发现 表pcz的确有194行。然后查看 索引 orders.dpcz_FK,表 orders  返回 1642行 ,因为外键约束 orders_ibfk_10 的定义,也就意味着 表 orders 的记录数应该是 194*1642=318548 ,但是实际的行数是 32508150,百倍于执行计划估计的值 318548 。

CREATE TABLE `orders` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
  `d_p_c_z_id` bigint(20) DEFAULT NULL,
  ...,
  PRIMARY KEY (`id`),
  ...
  KEY `dpcz_FK` (`d_p_c_z_id`),
  ...
  CONSTRAINT `orders_ibfk_10` FOREIGN KEY (`d_p_c_z_id`) REFERENCES `p_c_z` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ...
) ENGINE=InnoDB ....
mysql> select * from mysql.innodb_table_stats  where database_name='cutom' and table_name='orders';
+---------------+------------+---------------------+----------+----------------------+--------------------------+
| database_name | table_name | last_update         | n_rows   | clustered_index_size | sum_of_other_index_sizes |
+---------------+------------+---------------------+----------+----------------------+--------------------------+
| custom        | orders     | 2022-03-03 21:58:18 | 32508150 |               349120 |                   697618 |
+---------------+------------+---------------------+----------+----------------------+--------------------------+

分析至此,我们可以断定 orders.dpcz_FK 的统计信息是不准确的,于是乎我们使用如下语句确认它的实际数据量:

mysql> select * from mysql.innodb_index_stats where database_name='cutom' and table_name='orders' and index_name='dpcz_FK';
mysql> select * from mysql.innodb_index_stats  where database_name='custom' and table_name='orders' and index_name='dpcz_FK';
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update         | stat_name    | stat_value | sample_size | stat_description                  |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| custom        | orders     | dpcz_FK    | 2022-02-28 12:35:30 | n_diff_pfx01 |      19498 |          50 | d_p_c_z_id                        |
| custom        | orders     | dpcz_FK    | 2022-02-28 12:35:30 | n_diff_pfx02 |   32283087 |         128 | d_p_c_z_id,id                     |
| custom        | orders     | dpcz_FK    | 2022-02-28 12:35:30 | n_leaf_pages |      55653 |        NULL | Number of leaf pages in the index |
| custom        | orders     | dpcz_FK    | 2022-02-28 12:35:30 | size         |      63864 |        NULL | Number of pages in the index      |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
mysql> select count(distinct d_p_c_z_id) from orders; 
+----------------------------------------------+
| count(distinct d_p_c_z_id)                   |
+----------------------------------------------+
|                                          195 |
+----------------------------------------------+

Bingo!从上面来看 表 orders 字段 d_p_c_z_id 的区分度(不一样的值的总数)为 195 。在信息统计表里面 dpcz_FK的 stat_value 值是 19498 ,显然这个值是不准确的并且比实际值大的多,100倍 。索引的 state_value 值应该等于这个字段的在表里面的区分度。

如果使用正确的 索引 dpcz_FK 的值 stat_value  195 去重新评估执行计划的成本,我们将得到执行计划1 的结果  32508150/195=166708 ,并且执行计划预估的扫描的行数应该是 (194*10%)*166708*(1*4.23%)=136804。因为该值是10倍于执行计划2 的值 11045 。MySQL 在没有使用force index的情况下就能走到正确的执行计划 。

这个sql的问题解决了,但是为什么 MySQL 的统计信息会计算错误,我们如何修复它呢?

回答这个问题之前,我们先了解一下 MySQL 是如何收集统计信息以及哪些参数控制 这个动作。

InnoDB 是如何收集表的统计信息

我们可以通过显式的方式或者系统自动采集表的统计信息 。

通过开启参数innodb_stats_auto_recalc =on (默认也是打开的) 以便在表的数据发生重大变化以后来自动收集表的统计信息。比如当表中的10% 的行发生变化 ,InnoDB 将重新计算统计信息。或者我们可以使用ANALYZE TABLE显式地重新计算统计信息。

InnoDB 使用随机采样技术的方法采集统计信息-- 随机抽取索引页,估计索引的基数。参数 innodb_stats_persistent_sample_pages 控制采样页面的数量。参考 https://dev.mysql.com/doc/refman/5.7/en/innodb-persistent-stats.html

根据代码和描述,随机抽样并不是完全随机的。采样页面实际上是根据采样算法选择的。最终,不同键值的总数,即索引的 stat_value 将通过以下公式计算

N * R * N_DIFF_AVG_LEAF。其中

N : 叶页数
R : level LA上不同key值的个数与level LA上记录总数的比值
`N_DIFF_AVG_LEAF`:在所有 A 叶页中找到的不同键值的平均数。

采样算法代码的详细信息可以在链接中找到:https://github.com/mysql/mysql-server/blob/6846e6b2f72931991cc9fd589dc9946ea2ab58c9/storage/innobase/dict/dict0stats.cc

基于上面的介绍,我们知道当一个表的索引发生分裂时,无论是叶子页数(N),还是 层LA 上不同键值的个数占 层LA 总记录数的比值(R ) 变得越来越不准确,因此 stat_value 的计算可能不正确。一旦发生这种情况,除非更改参数innodb_stats_persistent_sample_pages或重建索引,否则显式重新计算(手动运行 ANALYZE TABLE)将无法生成正确的 stat_value。

解决方法

我们怎么修正表的统计信息 ,并且阻止这类情况进一步发生。

经过前面的分析和讨论,我们知道 有两个因素影响数据库收集表的统计信息 ,

innodb_stats_persistent_sample_pages: A

索引的组织方式

为了能够让 InnoDB 得到正确的 统计信息,我们需要 调整 innodb_stats_persistent_sample_pages 或者重建索引 。


1 通过命令 analyze table 不重建的方式,保持 innodb_stats_persistent_sample_pages =128,stat_value 略微更改为 19582,接近原始不正确的 19498,仍然关闭。索引中的叶子页数从 55653 略微更改为 55891,索引中的页数也从 63864 略微更改为 64248

mysql> show variables = 'innodb_stats_persistent_sample_pages;
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| innodb_stats_persistent_sample_pages | 128   |
+--------------------------------------+-------+
mysql> analyze table orders;
+---------------+---------+----------+----------+
| Table         | Op      | Msg_type | Msg_text |
+---------------+---------+----------+----------+
| custom.orders | analyze | status   | OK       |
+---------------+---------+----------+----------+
mysql> select * from mysql.innodb_index_stats  where database_name='custom' and table_name='orders' and index_name='dpcz_FK';
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update         | stat_name    | stat_value | sample_size | stat_description                  |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| custom        | orders     | dpcz_FK    | 2022-03-03 21:58:18 | n_diff_pfx01 |      19582 |          50 | d_p_c_z_id                        |
| custom        | orders     | dpcz_FK    | 2022-03-03 21:58:18 | n_diff_pfx02 |   32425512 |         128 | d_p_c_z_id,id                     |
| custom        | orders     | dpcz_FK    | 2022-03-03 21:58:18 | n_leaf_pages |      55891 |        NULL | Number of leaf pages in the index |
| custom        | orders     | dpcz_FK    | 2022-03-03 21:58:18 | size         |      64248 |        NULL | Number of pages in the index      |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+

2 ANALYZE TABLE 不重建,但将 innodb_stats_persistent_sample_pages 从 128 增加到 512,使 stat_value 到192非常接近实际基数 195。索引中的叶页数发生了很大变化,从 55653 到 44188。索引中的页数也从也发生了巨大变化,从 63864 变为 50304。

mysql> show variables like '%persistent_sample%';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| innodb_stats_persistent_sample_pages | 512   |
+--------------------------------------+-------+
mysql> analyze table orders;
+---------------+---------+----------+----------+
| Table         | Op      | Msg_type | Msg_text |
+---------------+---------+----------+----------+
| custom.orders | analyze | status   | OK       |
+---------------+---------+----------+----------+
mysql> select * from mysql.innodb_index_stats  where database_name='custom' and table_name='orders' and index_name='dpcz_FK';
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update         | stat_name    | stat_value | sample_size | stat_description                  |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| custom        | orders     | dpcz_FK    | 2022-03-09 06:54:29 | n_diff_pfx01 |        192 |         179 | d_p_c_z_id                        |
| custom        | orders     | dpcz_FK    | 2022-03-09 06:54:29 | n_diff_pfx02 |   31751321 |         512 | d_p_c_z_id,id                     |
| custom        | orders     | dpcz_FK    | 2022-03-09 06:54:29 | n_leaf_pages |      44188 |        NULL | Number of leaf pages in the index |
| custom        | orders     | dpcz_FK    | 2022-03-09 06:54:29 | size         |      50304 |        NULL | Number of pages in the index      |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+

3 重建表,保持 innodb_stats_persistent_sample_pages 为128,同样得到了正确的 stat_value 187,接近真实基数195。索引中的叶子页数大幅变化,从55653变为43733,索引中的页数也从63864变化到 50111。

mysql> show variables = 'innodb_stats_persistent_sample_pages';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| innodb_stats_persistent_sample_pages | 128   |
+--------------------------------------+-------+
mysql> alter table orders engine=innodb;
Query OK, 0 rows affected (11 min 16.37 sec)
mysql> select * from mysql.innodb_index_stats where database_name='custom' and table_name='orders' and index_name='dpcz_FK';
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update         | stat_name    | stat_value | sample_size | stat_description                  |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| custom        | orders     | dpcz_FK    | 2022-03-07 18:44:43 | n_diff_pfx01 |        187 |         128 | d_p_c_z_id                        |
| custom        | orders     | dpcz_FK    | 2022-03-07 18:44:43 | n_diff_pfx02 |   31531493 |         128 | d_p_c_z_id,id                     |
| custom        | orders     | dpcz_FK    | 2022-03-07 18:44:43 | n_leaf_pages |      43733 |        NULL | Number of leaf pages in the index |
| custom        | orders     | dpcz_FK    | 2022-03-07 18:44:43 | size         |      50111 |        NULL | Number of pages in the index      |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+

在更正表统计数据后,MySQL 优化器也会选择正确的执行计划:

mysql> explain
SELECT count(con.id)          ,
       MAX(DAYNAME(con.date)) ,
       now()                  ,
       pcz.type,
       pcz.c_c
FROM con AS con
         join orders o on con.order_id = o.id
         JOIN p_c_z AS pcz ON o.d_p_c_z_id = pcz.id
         left join c c on con.c_id = c.id
WHERE con.date = current_date()
and pcz.type = "T_D"
GROUP BY con.date, pcz.c_c,  pcz.type;
+----+-------------+-------+------------+--------+-------------------+----------+---------+---------------------------------------+------+----------+---------------------------------+
| id | select_type | table | partitions | type   | possible_keys     | key      | key_len | ref                                   | rows | filtered | Extra                           |
+----+-------------+-------+------------+--------+-------------------+----------+---------+---------------------------------------+------+----------+---------------------------------+
|  1 | SIMPLE      | con   | NULL       | ref    | FK_order,IDX_date | IDX_date | 3       | const                                 | 3074 |   100.00 | Using temporary; Using filesort |
|  1 | SIMPLE      | c     | NULL       | eq_ref | PRIMARY           | PRIMARY  | 8       | custom.con.c_id                       |    1 |   100.00 | Using index                     |
|  1 | SIMPLE      | o     | NULL       | eq_ref | PRIMARY,dpcz_FK   | PRIMARY  | 8       | custom.con.order_id                   |    1 |   100.00 | Using where                     |
|  1 | SIMPLE      | pcz   | NULL       | eq_ref | PRIMARY           | PRIMARY  | 8       | custom.o.d_p_c_z_id                   |    1 |    10.00 | Using where                     |
+----+-------------+-------+------------+--------+-------------------+----------+---------+---------------------------------------+------+----------+---------------------------------+
4 rows in set, 1 warning (0.01 sec)

结论

MySQL优化器依赖于表的统计信息的准确性来选择最优的执行计划。我们可以通过更改参数 innodb_stats_persistent_sample_pages 来控制系统采集表统计信息的准确性。

我们还可以选择通过在对索引进行碎片整理的同时重建/重建表来强制重新计算表统计信息,这有助于提高表统计信息的准确性。重构表,我们可以直接用 alter table xx; 修改表或者使用 pt-online-schema-change 达到同样的效果。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
14天前
|
SQL 关系型数据库 MySQL
MySQL 8.0:filesort 性能退化的问题分析
用户将 RDS MySQL 实例从 5.6 升级到 8.0 后,发现相同 SQL 的执行时间增长了十几倍。本文就该问题逐步展开排查,并最终定位根因。
|
24天前
|
SQL 关系型数据库 MySQL
【MySQL 慢查询秘籍】慢SQL无处遁形!实战指南:一步步教你揪出数据库性能杀手!
【8月更文挑战第24天】本文以教程形式深入探讨了MySQL慢SQL查询的分析与优化方法。首先介绍了如何配置MySQL以记录执行时间过长的SQL语句。接着,利用内置工具`mysqlslowlog`及第三方工具`pt-query-digest`对慢查询日志进行了详细分析。通过一个具体示例展示了可能导致性能瓶颈的查询,并提出了相应的优化策略,包括添加索引、缩小查询范围、使用`EXPLAIN`分析执行计划等。掌握这些技巧对于提升MySQL数据库性能具有重要意义。
50 1
|
27天前
|
缓存 关系型数据库 MySQL
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?
|
1月前
|
SQL 存储 关系型数据库
"MySQL增列必锁表?揭秘InnoDB在线DDL,让你的数据库操作飞一般,性能无忧!"
【8月更文挑战第11天】在数据库领域,MySQL凭借其稳定高效的表现深受开发者喜爱。对于是否会在给数据表添加列时锁表的问题,MySQL的行为受版本、存储引擎等因素影响。从5.6版起,InnoDB支持在线DDL,可在改动表结构时保持表的可访问性,避免长时间锁表。而MyISAM等则需锁表完成操作。例如,在使用InnoDB的表上运行`ALTER TABLE users ADD COLUMN email VARCHAR(255);`时,通常不会完全锁表。虽然在线DDL提高了灵活性,但复杂操作或大表变更仍可能暂时影响性能。因此,进行结构变更前应评估其影响并择机执行。
47 6
|
1月前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
1月前
|
存储 关系型数据库 MySQL
"揭秘!MySQL为何独宠B+树?跳表再牛,也敌不过这性能王者的N重诱惑!"
【8月更文挑战第11天】MySQL作为主流关系型数据库,优选B+树而非跳表作为索引结构,基于其对范围查询的支持、低磁盘I/O开销及事务处理能力。B+树叶节点构成有序链表,利于范围查询;较矮的树形结构减少了磁盘访问次数;支持多版本并发控制,保障事务ACID特性。而跳表在线性扫描范围查询时效率低,难以高效实现事务管理,且额外指针增加空间消耗。示例代码展示了B+树节点分裂过程,突显其内部机制。综上,B+树为MySQL提供了高性能、可靠的数据存储与检索能力。
43 4
|
17天前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
30 0
|
1月前
|
关系型数据库 MySQL OLTP
性能工具之 MySQL OLTP Sysbench BenchMark 测试示例
【8月更文挑战第6天】使用 pt-query-digest 工具分析 MySQL 慢日志性能工具之 MySQL OLTP Sysbench BenchMark 测试示例
155 0
性能工具之 MySQL OLTP Sysbench BenchMark 测试示例
|
24天前
|
缓存 关系型数据库 MySQL
【缓存大对决】Memcached VS MySQL查询缓存,谁才是真正的性能之王?
【8月更文挑战第24天】在现代Web应用中,缓存技术对于提升性能与响应速度至关重要。本文对比分析了Memcached与MySQL查询缓存这两种常用方案。Memcached是一款高性能分布式内存对象缓存系统,支持跨服务器共享缓存,具备灵活性与容错性,但受限于内存大小且不支持数据持久化。MySQL查询缓存内置在MySQL服务器中,简化了缓存管理,特别适用于重复查询,但功能较为单一且扩展性有限。两者各有所长,实际应用中可根据需求单独或结合使用,实现最佳性能优化。
47 0
|
27天前
|
关系型数据库 MySQL 数据库
如何利用MySQL建立覆盖原表的索引优化查询性能
通过合理使用覆盖索引,可以显著提高MySQL数据库的查询性能。然而,创建索引时需要仔细分析查询需求,合理设计索引结构,以确保索引能够发挥最大的效益。
28 0

热门文章

最新文章