055、查询优化之基于索引的优化

管理索引的方法

TiDB中的Online DDL

mysql> admin show ddl jobs;
+--------+---------+----------------------------------+--------------+--------------+-----------+----------+-----------+---------------------+---------------------+---------------------+--------+
| JOB_ID | DB_NAME | TABLE_NAME                       | JOB_TYPE     | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | CREATE_TIME         | START_TIME          | END_TIME            | STATE  |
+--------+---------+----------------------------------+--------------+--------------+-----------+----------+-----------+---------------------+---------------------+---------------------+--------+
|     68 | mysql   | advisory_locks                   | create table | public       |         3 |       67 |         0 | 2023-06-07 02:48:20 | 2023-06-07 02:48:20 | 2023-06-07 02:48:20 | synced |
|     66 | mysql   | analyze_jobs                     | create table | public       |         3 |       65 |         0 | 2023-06-07 02:48:20 | 2023-06-07 02:48:20 | 2023-06-07 02:48:20 | synced |

增加索引的原理

创建索引,会扫描全表
创建索原理简单而言:1、先创建元数据,2、再回填表(region)数据。
在这里插入图片描述

动态调整创建索引的速度

参数默认值说明
tidb_ddl_reorg_worker_nct4控制DDL操作re-organize阶段的并发度
tidb_ddl_reorg_batch_size256控制每个worker一起回填数据单位,以batch为单位
tidb_ddl_reorg_prioritypriority_low调整创建索引优先级,参数有 priority_low priority_normal priority_high
tidb_ddl_error_count_limit512失败重试次数,如果超过该次数创建索引会失败

在创建索引时,需要时刻关注:
- 创建索引对系统的压力,可以通过Grafana的dashboard来查看系统的压力
- 创建索引的速度,当系统压力不大的时候,可以适当调整创建索引的速度

在这里插入图片描述
注意: row_count 这个列来评估创建的速度

增加索引对于线上业务的影响

  • 目标列被频繁更新(DML)时,默认配置会造成较为频繁的写冲突,使得在线负载较大
  • 当add index的目标列仅涉及查询负载,或者与线上负载不直接相关时,可以直接使用默认配置
  • add index 也可能由于不断地重试,需要很长时间才能完成

目标列上存在频繁读写的场景

  • 无add index操作时:
    在这里插入图片描述
  • 有add index操作,且tidb_ddl_reorg_batch_size = 32 时:
    在这里插入图片描述
    在这里插入图片描述
    随着两个参数(tidb_ddl_reorg_worker_int 和tidb_ddl_reorg_batch_size)的逐渐增大,影响主要来源于add index与column update并发进行冲突的写冲突,系统的表现反应在:
  • tikv_prewrite_latch_wait_duration 有明显的升高,造成写入变慢。
  • admin show ddl 命令可以看到ddl job的多次重试,此时add index会持续非常久。

目标列上存在只读场景

  • 无add index操作时:
    在这里插入图片描述
  • 有add index操作,且tidb_ddl_reorg_batch_size = 32 时:
    在这里插入图片描述
    在这里插入图片描述

目标列不涉及读写场景

  • 无add index操作时:
    在这里插入图片描述
  • 有add index操作,且tidb_ddl_reorg_batch_size = 32 时:
    在这里插入图片描述

在这里插入图片描述

索引扫描方式

PointGet / Batch PointGet

要使得优化器能够选择PointGet算子,需要满足以下几个条件:

  • 返回值至多只能有一个,或者没有返回结果
  • 一定要有唯一键,可以是主键或者唯一索引

在这里插入图片描述

Index Full Scan

在这里插入图片描述
在这里插入图片描述

index range scan

对于非唯一索引,无论等值还是范围 都是Index Range scan
在这里插入图片描述
在这里插入图片描述

索引选择规则

索引选择的维度

在这里插入图片描述

  • 索引列涵盖了多少访问条件
    在这里插入图片描述
  • 索引是否需要回表
    • 不需要回表: indexRender
    • 需要回表: indexLookupRender

基于代价的选择

有以下因素决定:

  • 索引的每行数据在存储层的平均长度
  • 索引生成的查询范围的行数
  • 索引的回表代价
  • 索引查询时的范围数量

实验

观察索引的创建速度,并进行调整;
1、造数

mysql> create table t1(a int,b int);
Query OK, 0 rows affected (0.17 sec)

[root@tidb2 ~]# for i in `seq 10000`; do mysql -uroot -P4000 -h192.168.16.13 -pAa123ab! -e "insert into test.t1 values ($i,floor(rand()*10000000))"; done;

[root@tidb2 ~]# for i in `seq 33`; do mysql -uroot -P4000 -h192.168.16.13 -pAa123ab! -e "insert into test.t1 select * from test.t1 limit 100000"; done;

mysql> select count(*) from t1;
+----------+
| count(*) |
+----------+
|  3060000 |
+----------+
1 row in set (7.89 sec)

2、调慢创建索引的速度

mysql> set global tidb_ddl_reorg_worker_cnt=1;
Query OK, 0 rows affected (0.05 sec)

mysql> set global tidb_ddl_reorg_batch_size=32;
Query OK, 0 rows affected (0.10 sec)

3、创建索引,并观察创建索引的速度

mysql> create index idx_t1_a on t1(a);
Query OK, 0 rows affected (34 min 16.72 sec)

非常慢

mysql> admin show ddl jobs where table_name='t1';
+--------+---------+------------+----------------+----------------------+-----------+----------+-----------+---------------------+---------------------+---------------------+---------+
| JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE       | SCHEMA_STATE         | SCHEMA_ID | TABLE_ID | ROW_COUNT | CREATE_TIME         | START_TIME          | END_TIME            | STATE   |
+--------+---------+------------+----------------+----------------------+-----------+----------+-----------+---------------------+---------------------+---------------------+---------+
|    101 | test    | t1         | add index      | write reorganization |         1 |       99 |   2065666 | 2023-07-08 20:12:13 | 2023-07-08 20:12:13 | NULL                | running |
|    100 | test    | t1         | create table   | public               |         1 |       99 |         0 | 2023-07-08 19:56:50 | 2023-07-08 19:56:50 | 2023-07-08 19:56:51 | synced  |

+--------+---------+------------+----------------+----------------------+-----------+----------+-----------+---------------------+---------------------+---------------------+---------+
8 rows in set (0.02 sec)

4、调整参数,加快创建索引的速度

mysql> set global tidb_ddl_reorg_worker_cnt=32;
Query OK, 0 rows affected (0.05 sec)

mysql> set global tidb_ddl_reorg_batch_size=512;
Query OK, 0 rows affected (0.10 sec)

5、创建索引,并观察速度

mysql> create index idx_t1_a on t1(a);
Query OK, 0 rows affected (14 min 16.72 sec)

实验:点查

1、造数

mysql> create table t1( a int,b int);
Query OK, 0 rows affected (7 min 48.55 sec)
[root@tidb2 ~]# for i in `seq 10000`; do mysql -uroot -P4000 -h192.168.16.13 -pAa123ab! -e "insert into test.t1 values ($i,floor(rand()*10000000))"; done;

2、没有索引情况下,是否可以触发点查


mysql> explain select * from t1 where a = 88;
+-------------------------+----------+-----------+---------------+-------------------+
| id                      | estRows  | task      | access object | operator info     |
+-------------------------+----------+-----------+---------------+-------------------+
| TableReader_7           | 1.00     | root      |               | data:Selection_6  |
| └─Selection_6           | 1.00     | cop[tikv] |               | eq(test.t1.a, 88) |
|   └─TableFullScan_5     | 10000.00 | cop[tikv] | table:t1      | keep order:false  |
+-------------------------+----------+-----------+---------------+-------------------+
3 rows in set (0.00 sec)

4、创建非唯一索引后,是否会触发point get

mysql> create index idx on t1(a);
Query OK, 0 rows affected (4.06 sec)


mysql> explain select * from t1 where a = 88;
+-------------------------------+---------+-----------+------------------------+---------------------------------+
| id                            | estRows | task      | access object          | operator info                   |
+-------------------------------+---------+-----------+------------------------+---------------------------------+
| IndexLookUp_10                | 1.00    | root      |                        |                                 |
| ├─IndexRangeScan_8(Build)     | 1.00    | cop[tikv] | table:t1, index:idx(a) | range:[88,88], keep order:false |
| └─TableRowIDScan_9(Probe)     | 1.00    | cop[tikv] | table:t1               | keep order:false                |
+-------------------------------+---------+-----------+------------------------+---------------------------------+
3 rows in set (0.00 sec)

5、创建唯一索引,是否会触发点查

mysql> alter table t1 drop index idx;
Query OK, 0 rows affected (0.35 sec)

mysql> create unique index idx_unique on t1(a);
Query OK, 0 rows affected (4.31 sec)

mysql> explain select * from t1 where a = 88;
+-------------+---------+------+-------------------------------+---------------+
| id          | estRows | task | access object                 | operator info |
+-------------+---------+------+-------------------------------+---------------+
| Point_Get_1 | 1.00    | root | table:t1, index:idx_unique(a) |               |
+-------------+---------+------+-------------------------------+---------------+
1 row in set (0.00 sec)

6、唯一索引下的范围查询,是否会触发点查

mysql> explain select * from t1 where a < 10;
+-------------------------------+---------+-----------+-------------------------------+-----------------------------------+
| id                            | estRows | task      | access object                 | operator info                     |
+-------------------------------+---------+-----------+-------------------------------+-----------------------------------+
| IndexLookUp_10                | 9.00    | root      |                               |                                   |
| ├─IndexRangeScan_8(Build)     | 9.00    | cop[tikv] | table:t1, index:idx_unique(a) | range:[-inf,10), keep order:false |
| └─TableRowIDScan_9(Probe)     | 9.00    | cop[tikv] | table:t1                      | keep order:false                  |
+-------------------------------+---------+-----------+-------------------------------+-----------------------------------+
3 rows in set (0.00 sec)

7、有唯一索引,查询结果为空是否会触发point get

mysql> explain select * from t1 where a = -1;
+-------------+---------+------+-------------------------------+---------------+
| id          | estRows | task | access object                 | operator info |
+-------------+---------+------+-------------------------------+---------------+
| Point_Get_5 | 1.00    | root | table:t1, index:idx_unique(a) |               |
+-------------+---------+------+-------------------------------+---------------+
1 row in set (0.00 sec)

8、查询null 是否会触发点查

mysql> insert into t1 values (null,10000000);
Query OK, 1 row affected (0.01 sec)

m
ysql> explain select * from t1 where a = 88;
+-------------+---------+------+-------------------------------+---------------+
| id          | estRows | task | access object                 | operator info |
+-------------+---------+------+-------------------------------+---------------+
| Point_Get_1 | 1.00    | root | table:t1, index:idx_unique(a) |               |
+-------------+---------+------+-------------------------------+---------------+
1 row in set (0.00 sec)

mysql> explain select * from t1 where a is null;
+-------------------------------+---------+-----------+-------------------------------+-------------------------------------+
| id                            | estRows | task      | access object                 | operator info                       |
+-------------------------------+---------+-----------+-------------------------------+-------------------------------------+
| IndexLookUp_10                | 1.00    | root      |                               |                                     |
| ├─IndexRangeScan_8(Build)     | 1.00    | cop[tikv] | table:t1, index:idx_unique(a) | range:[NULL,NULL], keep order:false |
| └─TableRowIDScan_9(Probe)     | 1.00    | cop[tikv] | table:t1                      | keep order:false                    |
+-------------------------------+---------+-----------+-------------------------------+-------------------------------------+
3 rows in set (0.00 sec)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 不带优化的固定三级索引法是一种用于数据检索的技术,它将数据按照特定的规则分层存储,每一层都有对应的索引,以实现对数据的高效检索。该方法在实际应用中需要根据具体的数据结构和数据量进行优化,以提高检索效率和减少资源占用。 ### 回答2: 不带优化的固定三级索引法是一种简单的索引结构,用于加快在大型数据集中查找数据的速度。它通常由三个层次的索引构成,每个层次的索引都有一定的容量限制。 在这种索引结构中,最高级别的索引称为主索引,它包含了对数据集中所有索引项的引用。主索引的容量通常比较小,因此可以快速进行查找和遍历。 第二级别的索引称为辅助索引,它的每个索引项指向一组索引项,这些索引项在数据集中按照一定的规则进行划分。辅助索引的容量比主索引大,因此可以更高效地进行数据检索。 最低级别的索引称为终级索引,它包含了具体数据项的地址或指针。每个终级索引指向一个或多个实际存储数据的块或页。终级索引的容量最大,因为它们存储了实际的数据。 在使用不带优化的固定三级索引法时,我们需要在查询期间遵循一定的搜索路径。首先,在主索引中找到与查询条件相匹配的索引项。然后,使用该索引项指向的辅助索引来进一步缩小搜索范围。最后,在终级索引中找到满足查询条件的具体数据项。 由于不带优化的固定三级索引法没有采用任何优化技术,因此在查询大型数据集时可能会遇到访问磁盘频繁的问题。此外,索引的容量限制可能导致索引项的溢出和数据的分散存储,进一步降低了查询效率。 综上所述,不带优化的固定三级索引法是一种简单但效率相对较低的索引结构,适用于小型数据集或对查询性能要求不高的场景。 ### 回答3: 不带优化的固定三级索引法是一种简单但不高效的索引方法。它基于三级索引结构,即将数据分为三个级别的索引层次。 在这种索引方法中,将数据按照一定的规则划分为多个块,每个块包含一定数量的数据项。最底层是数据块,每个数据块包含多个数据项;中间一级是索引块,每个索引块指向多个数据块;最顶层是根索引块,指向多个索引块。 当需要进行查找时,首先在根索引块中查找,根据索引块的指针找到相应的索引块,再根据索引块中的指针找到对应的数据块。最终在数据块中找到目标记录。 然而,不带优化的固定三级索引法存在一些问题。首先,由于索引块和数据块的固定大小,当数据量增大时,需要增加索引块和数据块的数量,导致索引结构庞大,占用大量的存储空间。其次,由于索引块中只存储指针,而不存储实际数据,因此需要多次磁盘访问才能找到目标记录,访问效率低下。另外,如果数据的插入和删除频繁,索引结构可能会出现不均衡的情况,导致查找效率下降。 因此,在实际应用中,通常会对固定三级索引法进行优化,如使用动态调整索引块大小、引入多级索引、使用排序等方法来提高索引的效率和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值