MySql中走索引的判定

如何判断一条sql走哪个索引

一条sql在MySql中的执行,要经历分析器、优化器、执行器。

这条sql走不走索引、走哪个索引,是在优化器中进行的,sql优化器会列出这条sql的所有可能的执行计划,会根据一定的规则,来对每一个执行计划来进行分析,最后决定选择哪个执行计划,是通过最后的计算成本来得到的。

计算一条sql的成本

SQL优化器将分析所有可能的执行计划,并选择成本最低的执行。这个优化器被称为CBO(基于成本的优化器)。

在 MySQL中,一条 SQL 的计算成本计算,很好理解,就是访问数据库(数据库页、磁盘)+处理数据。

CPU成本,表示计算成本,例如索引键值的比较、记录值的比较和结果集的排序。这些操作都在服务器层完成

IO成本,表示引擎级IO的成本,MySQL 8.0可以通过区分表的数据是否在内存中来分别计算读取内存IO和磁盘IO的成本。

Cost = Server Cost + Engine Cost = CPU Cost + IO Cost

MySQL优化器认为:

如果一段SQL需要创建一个基于磁盘的临时表,此时成本最大,是基于内存的临时表的20倍。比较索引键值和记录的成本很低,但如果要比较的记录很多,成本就会非常大。

从磁盘读取的开销是内存开销的 4 倍(成本不是一成不变的会根据硬件变化)。

查看sql的运行成本:

EXPLAIN FORMAT=json select ...

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "1.41"
    },
    "table": {
      "table_name": "t",
      "access_type": "range",
      "possible_keys": [
        "idx_a_b"
      ],
      "key": "idx_a_b",
      "used_key_parts": [ // 使用了索引的键
        "a"
      ],
      "key_length": "5",
      "rows_examined_per_scan": 2,
      "rows_produced_per_join": 1,
      "filtered": "50.00",
      "index_condition": "((`testdb`.`t`.`b` = 2) and (`testdb`.`t`.`a` <> 2))",
      "cost_info": {
        "read_cost": "1.31",       // 表示从InnoDB存储引擎读取的成本
        "eval_cost": "0.10",       // 表示服务器层的CPU成本
        "prefix_cost": "1.41",     // 表示SQL的总成本
        "data_read_per_join": "16" // 表示读取记录中的字节总数
      },
      "used_columns": [
        "a",
        "b",
        "c"
      ]
    }
  }
}

ead_cost 表示从InnoDB存储引擎读取的成本;

eval_cost 表示服务器层的CPU成本;

prefix_cost 表示SQL的总成本;

data_read_per_join 表示读取记录中的字节总数。

MySql索引的采样统计

MySql的索引,是通过采样统计的方法来得到的

InnoDB 默认会选择 N 个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。

而数据表是会持续更新的,索引统计信息也不会固定不变。所以,当变更的数据行数超过 1/M 的时候,会自动触发重新做一次索引统计。

在 MySQL 中,有两种存储索引统计的方式,可以通过设置参数 innodb_stats_persistent 的值来选择:

  1. 设置为 on 的时候,表示统计信息会持久化存储。这时,默认的 N 是 20,M 是 10。
  2. 设置为 off 的时候,表示统计信息只存储在内存中。这时,默认的 N 是 8,M 是 16。

由于是采样统计,所以不管 N 是 20 还是 8,这个基数都是很容易不准的,但是大体上差不多。

解决不走索引的办法

  1. 使用 analyze 重新统计索引信息
  2. 加 force index
  3. 删除误走的索引
  4. 新建更好的索引

参考:
https://m.php.cn/faq/497571.html
https://aiguangyuan.blog.csdn.net/article/details/109664294

你可能感兴趣的:(mysql,数据库,索引,InnoDB)