mysql的索引分类和索引优化

索引介绍

  • 索引是帮助MySQL高效获取数据的排好序的数据结构;存储的内容是指向表中数据的指针

  • mysql有多种索引,B+tree索引,全文索引,哈希索引、空间索引。其中以B+Tree索引应用最为广泛

假设从0到1000中,猜一个数字。结果只有对、错2种,猜错时会提示猜大了还是小了。猜对的次数会随着数字基数的增大而增加,这就类似于一颗二叉树。

在这里插入图片描述

B-tree索引

**数据存储:**节点(内部节点和叶子节点)都可以存储数据,非叶子节点也存储数据和指向子节点的指针

**链式结构:**叶子节点之间没有链式连接,数据查找必须在树上进行遍历,无法顺序读取所有数据。因此范围查询时效率差

**树的层数:**非叶子节点也存储数据,B树的每个节点可以容纳的数据较少,因此树的高度相对较高

在这里插入图片描述

B+Tree索引

B-Tree和B+Tree的对比表

比较维度B树B+树
数据存储位置数据存储在所有节点(包括内部节点和叶子节点)数据仅存储在叶子节点,内部节点只存储索引
叶子节点链表叶子节点之间无链表叶子节点通过链表相连,方便顺序遍历
树的高度相对较高相对较低,内部节点可容纳更多索引
数据访问效率可能提前在非叶子节点找到数据查找时需到叶子节点,效率稳定
范围查询效率不适合范围查询通过叶子节点的链表结构,范围查询效率高
磁盘I/O性能相对较差,节点存储数据和索引占用磁盘空间更少,I/O 性能较好

可视化B+Tree操作在这里插入图片描述

  • 数据写入时,把数据均匀的写入到磁盘中。根据页节点的存储信息,取出边界值(最大值或最小值)。并将每个叶节点最大数据信息进行汇总整合
  • B+Tree增加了同级相邻叶子节点之间的双向指针,从而实现相邻节点相互跳转。往右跳转SELECT * FROM table WHERE id > 5
  • 树越往上,索引范围越大,存储更多的索引
  • 将需要存储的数据信息,均匀分配保存到对应页当中,最终数据信息的均匀存储
  • 在进行等值数据查询时,每次查询消耗的IO数量相等

BTree索引的优势介绍

  • 擅于等值和范围查询数据
  • 树的结构层次是(根 支 页),跟和枝存储的是指针信息,叶子节点存储的是数据信息
  • 在 inodb中,通常设置 主键索引和 辅助索引

索引分类

主键索引

在这里插入图片描述

:主键索引也叫聚簇索引

聚簇索引主要是:将多个簇(区-64个数据页-1M)聚集在一起就构成了所谓聚簇索引,也可以称之为主键索引;

聚簇索引作用是:用来组织存储表的数据行信息的,也可以理解为数据行信息都是按照聚簇索引结构进行存储的,即按区分配空间的;

聚簇索引的存储:聚簇是多个簇,簇是多个连续数据页(64个),页是多个连续数据块(4个),块是多个连续扇区(8个);

如果没有定义主键,InnoDB会尝试选择第一个唯一且非空的索引作为聚簇索引

  • 特点是存储数据的顺序和索引顺序一致
  • 叶子节点包含一条完整的记录
# innodb world库目录下,只有3个文件(对应3张表),目录和索引全在一个文件内。而myisam引擎索引和数据是分散的
[root@db01world]# pwd
/data/3306/data/world
[root@db01world]# ls
city.ibd  country.ibd  countrylanguage.ibd

构建过程:

  • 数据表创建时,显示的构建了主键信息(pk),主键(pk)就是聚簇索引;
  • 数据表创建时,没有显示的构建主键信息时,会将第一个不为空的UK的列做为聚簇索引;
  • 数据表创建时,以上条件都不符合时,生成一个6字节的隐藏列,row ID作为聚簇索引;

为什么建议使用自增主键建立索引?

  • 如果使用字符作为索引,mysql会比对编码转成2进制数字,数字会比较长,然后在使用数字建立索引
  • 直接使用一个int主键作为索引,减少了转换,所以快速

辅助索引

辅助索引介绍

  • 创建表时,显示的一般索引信息就是辅助索引

  • 没有辅助索引就会进行全表扫描

  • 非主键索引结构叶子节点存储的是主键值(一致性和节省存储空间)

  • 有唯一性设置的辅助索引优先级比其他没有设置唯一性索引高

==场景:==如果不知道信息的id,只知道name=wzy,怎么找到这一行数据

假设普通查询:select * from table where name='x';

范围查询:**`select * from table where name like '%x%';`**

1️⃣以name为x进行聚簇查询,得到name为x的记录信息,并查出id=y

2️⃣然后用 select * from table whre id=y; 回表查询,然后得出整个信息

3️⃣辅助索引存储的值是主键索引

在这里插入图片描述

辅助索引的构建

int(数字)类型可以排序,char(字符串)也可以排序,

在这里插入图片描述

查看主键|辅助索引

在这里插入图片描述

1.查看表结构

mysql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| ID          | int      | NO   | PRI | NULL    | auto_increment |
| Name        | char(35) | NO   |     |         |                |
| CountryCode | char(3)  | NO   | MUL |         |                |
| District    | char(20) | NO   |     |         |                |
| Population  | int      | NO   |     | 0       |                |
+-------------+----------+------+-----+---------+----------------+

2.查看建表语句,包含了索引设置

show CREATE TABLE city;CREATE TABLE `city` (`ID` int NOT NULL AUTO_INCREMENT,`Name` char(35) NOT NULL DEFAULT '',`CountryCode` char(3) NOT NULL DEFAULT '',`District` char(20) NOT NULL DEFAULT '',`Population` int NOT NULL DEFAULT '0',PRIMARY KEY (`ID`),KEY `CountryCode` (`CountryCode`),CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `country` (`Code`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;

3.查看索引的详细信息

mysql> show index from city;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| city  |          0 | PRIMARY     |            1 | ID          | A         |        4188 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| city  |          1 | CountryCode |            1 | CountryCode | A         |         232 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

索引中的字段说明

字段说明:

  • Table:表的名称,这里是 city
  • Non_unique:是否允许重复值(即该索引是否唯一);0 表示索引是唯一的(如 PRIMARY索引),1 表示索引可以包含重复的值
  • Key_name:索引的名称。PRIMARY 是主键索引的名称,CountryCode 是非唯一索引的名称
  • Seq_in_index:索引中列的顺序。对于复合索引(包含多个列),指示该列在索引中的位置,1 表示这是索引中的第一个列
  • Column_name:该索引所包含的列名。对于 PRIMARY 索引,列名是 ID。对于 CountryCode 索引,列名是 CountryCode
  • Collation:索引中的列的排序规则。通常为 A 表示按升序排序
  • Cardinality:索引的基数,表示该列中不同值的数量
  • Sub_part:如果索引只使用列的部分字符长度,该列的长度。NULL 表示索引使用整个列的值
  • Packed:索引是否已压缩。NULL 表示没有压缩
  • Null:指示该列是否允许 NULL 值。若允许 NULL,则显示 YES,否则为空(表示不允许 NULL 值)
  • Index_type:索引的类型,常见的有 BTREEHASH 等。这里使用的是 BTREE,表示该索引使用的是 B+Tree 结构
  • Comment:索引的备注信息。为空表示没有备注
  • Visible:索引是否有效。YES 表示索引有效,可以被查询使用。否则就是处于被禁用状态
  • Expression:如果该索引是基于表达式生成的(例如在索引中包含计算结果),则显示表达式的内容。如果是普通列索引,则为 NULL

前缀索引

MySQL 的 前缀索引 在存储**长文本(如 VARCHARTEXT)**时,比较有用。前缀索引是指创建索引时,只对列的前几个字符进行索引,而不是对整列数据进行索引。能够显著减少索引的存储空间,并在查询时提高效率

1.假设有一个包含用户信息的表 users,其中包含一个 email 字段,存储每个用户的电子邮件地址。如果有数百万条记录,email 列包含的是用户的电子邮件地址,而这些地址通常有很多相似的部分(如 @gmail.com@mail.com 等)。如果我们为 email 列创建一个普通的 全文索引,这会导致非常大的索引文件,并且查询效率也不一定很高。

CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100),email VARCHAR(255)
);

2.使用前缀索引。可以只对邮箱的前缀部分进行索引,

CREATE INDEX email_prefix_idx ON users(email(10));

3.查看索引信息

mysql> desc users;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int          | NO   | PRI | NULL    | auto_increment |
| name  | varchar(100) | YES  |     | NULL    |                |
| email | varchar(255) | YES  | MUL | NULL    |                |
+-------+--------------+------+-----+---------+----------------+
mysql> show index from users;
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users |          0 | PRIMARY          |            1 | id          | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| users |          1 | email_prefix_idx |            1 | email       | A         |           0 |       10 |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

4.注意:使用 where email LIKE '%@gmail.com' 将无法利用前缀索引,

正确的为:SELECT * FROM users WHERE email LIKE 'john%';

哈希索引

  • 哈希索引 主要用于 Memory 引擎,适用于 等值查询,可以提供 O(1) 的查找效率
  • 哈希对于范围查询、排序 或其他非等值查询无效
  • 如果数据量过大,哈希表可能会变得拥挤,导致 哈希冲突 增加,性能反而下降

1.假设有一个 users 表,包含以下数据:

CREATE TABLE users (user_id INT,username VARCHAR(50),email VARCHAR(100),PRIMARY KEY (user_id)
) ENGINE=InnoDB;

2.有一个查询需求:根据电子邮件查询用户信息

SELECT * FROM users WHERE email = 'wenzhiyong@qq.com';

如果针对 email 字段没有任何索引,那么mysql会执行全表扫描查找

3.可以对 email 设置一个哈希索引

哈希索引会将 email 的值通过哈希函数计算出一个哈希值,并直接定位到哈希表中相应的位置。这意味着查询的时间复杂度是 O(1),查询时间和数据量无关

CREATE TABLE users_hash (user_id INT,username VARCHAR(50),email VARCHAR(100),PRIMARY KEY (user_id),KEY (email) USING HASH    # 使用哈希索引
) ENGINE=MEMORY;

4.注意哈希索引不能用于 排序 或 范围查询,例如:

SELECT * FROM users_hash WHERE email > 'wzy@qq.com';
SELECT * FROM users_hash WHERE email > '%wzy@mail.com%';

联合索引

  • 联合索引的列顺序需要与查询条件的列顺序匹配,否则索引失效,即最左匹配原则

1.假设有一个这样的订单表

CREATE TABLE orders (order_id INT AUTO_INCREMENT PRIMARY KEY,  # 订单idcustomer_id INT,                          # 客户 IDorder_date DATE,                          # 订单日期total_amount DECIMAL(10, 2),              # 订单总金额 status VARCHAR(20)                        # 订单状态(例如:已发货、待付款等)
);

有2条独立的索引:基于 客户id 的和 基于订单日期的

CREATE INDEX idx_customer_id ON orders (customer_id);
CREATE INDEX idx_order_date ON orders (order_date);

2.有如下查询需求

查询某个客户在特定日期范围内的所有订单:

SELECT * FROM orders 
WHERE customer_id = 123 
AND order_date BETWEEN '2024-01-01' AND '2024-01-31';

查询某个客户所有已发货订单的总金额:

SELECT SUM(total_amount) FROM orders 
WHERE customer_id = 123 
AND status = 'Shipped';

3.先分析一下未使用联合索引时的查询情况

SELECT * FROM orders WHERE customer_id = 123 AND order_date = '2024-01-01';

MySQL 首先会使用 idx_customer_id 来查找所有 customer_id = 123 的记录,然后,MySQL 会使用 idx_order_date 来查找所有 order_date = '2024-01-01' 的记录。最后MySQL 会 合并 这两个结果集,找出既符合 customer_id = 123 又符合 order_date = '2024-01-01' 的记录

这里就涉及到索引合并:

  • 索引合并需要先分别扫描两个索引,消耗额外的计算资源
  • 然后还要合并两个结果集,导致更多的计算和内存开销

4.以 客户id 和 订单日期创建一条联合索引

CREATE INDEX idx_customer_date ON orders (customer_id, order_date);

5.当有如下查询时:

SELECT * FROM orders WHERE customer_id = 123 AND order_date = '2024-01-01';

MySQL 会直接使用 idx_customer_date 联合索引,这样只需要 一次扫描,而不需要扫描两个索引再进行合并。由于只有一次扫描,查询效率更高,性能也更好

6.如果查询的列并没有出现在联合索引的最前面,索引将无法被有效利用。例如:

SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31';

因为 order_date 并不是联合索引的第一个列,所以联合索引失效了

7.查看 orders 的索引情况

mysql> show index from orders;
+--------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table  | Non_unique | Key_name          | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| orders |          0 | PRIMARY           |            1 | order_id    | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| orders |          1 | idx_customer_date |            1 | customer_id | A         |           0 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| orders |          1 | idx_customer_date |            2 | order_date  | A         |           0 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+--------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

PRI聚簇、主键索引

MUL辅助索引

mysql> show index from world.city;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| city  |          0 | PRIMARY     |            1 | ID          | A         |        4046 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| city  |          1 | CountryCode |            1 | CountryCode | A         |         232 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

1️⃣Non_unique=0表示唯一索引,1 表示可以重复

2️⃣Collation: 显示创建索引排序方式 A:升序 D:降序

3️⃣Cardinality:显示索引列的索引选择度,数据库会自动计算估值,索引列数据重复情况
4188/4079 约等于 1 重复值越少

选择度 = (唯一索引值的数量 / 总记录数)

  • 选择度接近1:表示索引的选择性很好,索引列中的值几乎不重复。
  • 选择度接近0:表示索引的选择性很差,索引列中的值大部分或全部相同。

索引的创建/删除

创建索引

1.创建表时就创建索引

create table t1 (id int, name varchar(255), primary key(id));

2.创建表后再创建索引

mysql> create table t1 (id int, name varchar(255));
mysql> desc t1;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int          | YES  |     | NULL    |       |
| name  | varchar(255) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+# 添加主键索引
mysql> alter table t1 add primary key (id);

辅助索引创建

 create table t1 (id int, name char(10), index index_name(name));mysql> desc t1;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int      | YES  |     | NULL    |       |
| name  | char(10) | YES  | MUL | NULL    |       |
+-------+----------+------+-----+---------+-------+
-- 索引信息:辅助索引 
alter table test01 add index idx_name(name);
alter table test01 add index idx_name(name(length));  -- 设置前缀,length可选项
alter table test04 add index xiaoA(name desc) ;       -- 调整排序方
  • 只创建一个辅助索引
create table t1 (id int, name char(10), unique index index_name(name));

尽量遵循最左最高原则

  • 多列索引,(联合索引)
create table t01 (id int,name char(10),age char(5),index index_name(name,age));

select * from t01 where name='xx' and age=20;

当出现重名时,设置2个条件以减少回表数量,联合索引减少IO的更多

索引覆盖

覆盖索引(Covering Index)是指在查询执行过程中,索引本身包含了查询所需要的所有列,因此 MySQL 可以直接通过索引获取查询结果,而无需访问表中的实际数据行。也就是说,查询所需的所有数据都在索引中,不需要回表(即不需要访问表的数据页)

1.假设有1个员工表

CREATE TABLE employees (emp_id INT PRIMARY KEY,   # 员工idfirst_name VARCHAR(50),   # 姓氏last_name VARCHAR(50),    # 名字department VARCHAR(50),   # 任职部门salary DECIMAL(10, 2)     # 薪资
);

2.基于姓名创建一个联合索引,首先通过主键索引(PRIMARY KEY)定位到符合 emp_id = 1001 的数据行;然后,MySQL 会回表,访问数据行,取出 first_namelast_name 字段的值

CREATE INDEX idx_name ON employees(first_name, last_name);

3.没有覆盖索引方式查询员工姓名

SELECT first_name, last_name FROM employees WHERE emp_id = 1001;

4.使用覆盖索引方式查询员工姓名

SELECT first_name, last_name FROM employees WHERE first_name = 'John' AND last_name = 'Doe';

创建索引时的注意事项

  • 创建辅助索引时,考虑回表次数,尽可能降低回表次数

  • 使用覆盖索引,即索引本身包含了查询所需要的所有列

    • select name from user whrere name='wzy' and password='wzy666'
      
  • 树的高度越低越好

  • 数据量过大可以分库分表

删除索引

3)删除索引
聚簇索引删除 
alter table t100x drop primary key;
辅助索引删除:
alter table t100w drop index idx_name;  
mysql> show index from t01;
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| t01   |          1 | index_name |            1 | name        | A         |           0 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| t01   |          1 | index_name |            2 | age         | A         |           0 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
mysql> alter table t01 drop index index_name; 
Query OK, 0 rows affected (0.01 sec)

临时禁用索引

alter table city alter index CountryCode invisible;
alter table city alter index CountryCode visible;

查询压测数据库

1.准备测试的数据,插入100万条数据

mysql> CREATE TABLE `t100w` (`id` int DEFAULT NULL,`num` int DEFAULT NULL,`k1` char(2) DEFAULT NULL,`k2` char(4) DEFAULT NULL,`dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;mysql> desc t100w;
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| Field | Type      | Null | Key | Default           | Extra                                         |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| id    | int       | YES  |     | NULL              |                                               |
| num   | int       | YES  |     | NULL              |                                               |
| k1    | char(2)   | YES  |     | NULL              |                                               |
| k2    | char(4)   | YES  |     | NULL              |                                               |
| dt    | timestamp | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+mysql> select * from t100w limit 10;
+------+--------+------+------+---------------------+
| id   | num    | k1   | k2   | dt                  |
+------+--------+------+------+---------------------+
|    1 |  25503 | 0M   | IJ56 | 2019-08-12 11:41:16 |
|    2 | 756660 | rx   | bc67 | 2019-08-12 11:41:16 |
|    3 | 876710 | 2m   | tu67 | 2019-08-12 11:41:16 |
|    4 | 279106 | E0   | VWtu | 2019-08-12 11:41:16 |
|    5 | 641631 | At   | rsEF | 2019-08-12 11:41:16 |
|    6 | 584039 | QJ   | VWlm | 2019-08-12 11:41:16 |
|    7 | 541486 | vc   | ijKL | 2019-08-12 11:41:16 |
|    8 | 771751 | 47   | ghLM | 2019-08-12 11:41:16 |
|    9 | 752847 | aQ   | CDno | 2019-08-12 11:41:16 |
|   10 | 913759 | ej   | EFfg | 2019-08-12 11:41:16 |
+------+--------+------+------+---------------------+

2.执行压测命令

mysqlslap \
--defaults-file=/data/3306/my.cnf \
--concurrency=100 \
--iterations=1 \
--create-schema='zhiyong18' \
--query="select * from zhiyong18.t100w where k2='VWlm'" \
engine=innodb \
--number-of-queries=2000 \
-uroot -paa -h10.0.0.51 \
-verbose

--concurrency=100:模拟的并发用户数为 100,即每个并发用户都会执行相同的查询

--iterations=1:执行一次测试

--create-schema='zhiyong18':在运行查询之前创建一个名为 zhiyong18 的数据库架构(如果该数据库不存在)。注意,mysqlslap 会尝试创建此数据库,但不会删除已存在的数据库

--number-of-queries=2000:每个并发用户会执行 2000 次查询操作

3.可以发现主机负载异常的高,查询耗时也比较长

[root@db51~]# uptime23:23:59 up  9:06,  3 users,  load average: 84.14, 40.37, 17.14
[root@db51~]# top -bn1 | grep -A 1 '%CPU'PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND1319 mysql     20   0 7063820 573312  17844 S  1194 28.3  39:03.62 mysqld

4.对 k2 列增加辅助索引

mysql> alter table t100w add index idx_k2(k2);
Query OK, 0 rows affected (2.28 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> desc t100w;
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| Field | Type      | Null | Key | Default           | Extra                                         |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| id    | int       | YES  |     | NULL              |                                               |
| num   | int       | YES  |     | NULL              |                                               |
| k1    | char(2)   | YES  |     | NULL              |                                               |
| k2    | char(4)   | YES  | MUL | NULL              |                                               |
| dt    | timestamp | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+

5.再次压测,不到4秒就压测完毕,效果明显

[root@db51~]# mysqlslap \
> --defaults-file=/data/3306/my.cnf \
> --concurrency=100 \
> --iterations=1 \
> --create-schema='zhiyong18' \
> --query="select * from zhiyong18.t100w where k2='VWlm'" \
> engine=innodb \
> --number-of-queries=2000 \
> -uroot -paa -h10.0.0.51 \
> -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
BenchmarkRunning for engine rboseAverage number of seconds to run all queries: 3.737 secondsMinimum number of seconds to run all queries: 3.737 secondsMaximum number of seconds to run all queries: 3.737 secondsNumber of clients running queries: 100Average number of queries per client: 20

索引优化

常规索引优化

总结:

  • 最好有主键索引

  • 选择索引选择度高的列作为索引

  • 配置了联合索引,要按最左匹配原则

  • 创建辅助索引,前缀索引

  • 少用 >,like 等筛选条件

  • 注意观察执行计划的type

  • 关注执行计划Extra 是否为 using where,全表扫描

在这里插入图片描述

  • 因为是范围查找,所以name字段失效。
select * from table where age>100 and name=wzy;

正确写法:

select * from table where name=wzy and age>100;
  • 不低于
select name =! 'wzy';
  • 以通配符开头
select name like '%wzy';
  • or或者

AHI功能

AHI全称(中文名称)为自适应的hash索引/散列索引,用于在内存中建立索引,快速锁定内存中的热点数据索引页位置;

正常情况下,所有数据都是存储在磁盘中的,如果想访问读取相应磁盘的数据信息,都是会将磁盘数据调取存放在内存中,即消耗IO;

对于数据库服务而言,想要读取数据信息,也是会从磁盘中读取存储页,在放入内存中被数据库服务进行访问,索引访问也是一样的;

但是当数据页大量的被存放在内存中后,从大量内存中的数据页找到想要的,也是比较困难的事情;

因此,可以对内存中经常被访问数据索引页建立一个hash索引,从而可以帮助数据库服务快速定位内存中想要找的索引数据页;

在这里插入图片描述

mysql> show variables like 'innodb_adaptive_hash_index';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_adaptive_hash_index | ON    |
+----------------------------+-------+

change_buffer调整

change_buffer 与 InnoDB 存储引擎中的写入缓冲区有关。它主要用于加速写入操作,尤其是对非主键索引的插入、更新和删除操作

1.change_buffer 的大小,说明默认为内存的25%

mysql> show variables like '%change_buffer%';
+-----------------------------------------+-------+
| Variable_name                           | Value |
+-----------------------------------------+-------+
| innodb_change_buffer_max_size           | 25    |
| innodb_change_buffering                 | all   |
+-----------------------------------------+-------+

预读功能

当使用这样的查询时,k2 结果集超过总数据量的25%时,优化器就不走索引了。而是走预读功能

select * from t100w where k2='a00' or k2='a01' k2='a02' k2='a03'

索引元信息

select * from mysql.innodb_index_stats;select * from mysql.innodb_table_stats;
  • 在数据表中插入 修改 删除数据时,聚簇索引树会进行同步实时更新,辅助索引树会进行异步延时更新

  • 数据频繁写入的时候会触发索引元数据锁,导致数据不能写入

    • 解决方法:先临时放在change buffer区域,积攒一定数据量再修改索引结构
mysql> select * from mysql.innodb_index_stats where database_name='world' and table_name='city';
+---------------+------------+--------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name   | last_update         | stat_name    | stat_value | sample_size | stat_description                  |
+---------------+------------+--------------+---------------------+--------------+------------+-------------+-----------------------------------+
| world         | city       | CountryCode  | 2024-12-01 18:46:24 | n_diff_pfx01 |        232 |           7 | CountryCode                       |
| world         | city       | CountryCode  | 2024-12-01 18:46:24 | n_diff_pfx02 |       4079 |           7 | CountryCode,ID                    |
| world         | city       | CountryCode  | 2024-12-01 18:46:24 | n_leaf_pages |          7 |        NULL | Number of leaf pages in the index |
| world         | city       | CountryCode  | 2024-12-01 18:46:24 | size         |          8 |        NULL | Number of pages in the index      |
| world         | city       | PRIMARY      | 2024-12-01 18:46:24 | n_diff_pfx01 |       4188 |          20 | ID                                |
| world         | city       | PRIMARY      | 2024-12-01 18:46:24 | n_leaf_pages |         24 |        NULL | Number of leaf pages in the index |
| world         | city       | PRIMARY      | 2024-12-01 18:46:24 | size         |         25 |        NULL | Number of pages in the index      |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | n_diff_pfx01 |        232 |           5 | CountryCode                       |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | n_diff_pfx02 |       4052 |           5 | CountryCode,Population            |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | n_diff_pfx03 |       4079 |           5 | CountryCode,Population,ID         |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | n_leaf_pages |          5 |        NULL | Number of leaf pages in the index |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | size         |          6 |        NULL | Number of pages in the index      |
+---------------+------------+--------------+---------------------+--------------+------------+-------------+-----------------------------------+
iff_pfx01 |        232 |           5 | CountryCode                       |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | n_diff_pfx02 |       4052 |           5 | CountryCode,Population            |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | n_diff_pfx03 |       4079 |           5 | CountryCode,Population,ID         |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | n_leaf_pages |          5 |        NULL | Number of leaf pages in the index |
| world         | city       | idx_code_pop | 2024-12-01 18:46:24 | size         |          6 |        NULL | Number of pages in the index      |
+---------------+------------+--------------+---------------------+--------------+------------+-------------+-----------------------------------+

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/888848.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

短视频矩阵系统开发|技术源代码部署

短视频矩阵系统通过多账号运营管理、多平台视频智能分发等功能,助力企业实现视频引流、粉丝沉淀和转化。 短视频矩阵系统是一种创新的营销工具,它整合了多账号管理、视频智能分发、数据可视化等多种功能,为企业在短视频领域的发展提供了强大…

计算机网络研究实训室建设方案

一、概述 本方案旨在规划并实施一个先进的计算机网络研究实训室,旨在为学生提供一个深入学习、实践和研究网络技术的平台。实训室将集教学、实验、研究于一体,覆盖网络基础、网络架构、网络安全、网络管理等多个领域,以培养具备扎实理论基础…

【开源免费】基于SpringBoot+Vue.JS中小型医院网站(JAVA毕业设计)

博主说明:本文项目编号 T 078 ,文末自助获取源码 \color{red}{T078,文末自助获取源码} T078,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

Wireshark数据抓包分析之传输层协议(TCP协议)

根据实验环境,本实验的步骤如下: 1.在测试环境使用发包工具和Wireshark抓取TCP三次握手和四次断开的数据包。 2.详细分析TCP协议的三次握手以及四次断开。 任务描述:安装发包工具,并配置TCP客户端,服务端&#xff0…

【目标检测】【反无人机目标检测】使用SEB-YOLOv8s实时检测未经授权的无人机

Real-Time Detection of Unauthorized Unmanned Aerial Vehicles Using SEB-YOLOv8s 使用SEB-YOLOv8s实时检测未经授权的无人机 论文链接 0.论文摘要 摘要:针对无人机的实时检测,复杂背景下无人机小目标容易漏检、难以检测的问题。为了在降低内存和计算…

Flume基础概念

目录 作用组件构成ClientFlowAgentSourceSinkEvent 和Log4j的区别与定位事务传出流程输入到sourcesource端输入Channel 接收输入到SinkSink输出 作用 Flume可以从各种来源(如日志文件、消息队列、网络数据、文件系统、数据库等)收集数据,并将…

Unity 设计模式-观察者模式(Observer Pattern)详解

观察者模式 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。这种模式用于事件处理系…

论文:IoU Loss for 2D/3D Object Detection

摘要:在2D/3D目标检测任务中,IoU (Intersection-over- Union)作为一种评价指标,被广泛用于评价不同探测器在测试阶段的性能。然而,在训练阶段,通常采用常见的距离损失(如L1或L2)作为损失函数,以最小化预测值…

vue.js学习(day 20)

综合案例:购物车 数据渲染 构建cart购物车模块 准备后端接口服务环境 请求数据存入vuex cart.js // 新建购物车模块 import axios from axios export default {namespaced: true,state () {return {// 购物车数据 [{},{}]list: []}},mutations: {updateList (…

RAG系统分类、评估方法与未来方向

分享一篇RAG综述:Retrieval-Augmented Generation for Large Language Models: A Survey,主要想了解一下RAG的评估方法,分享给大家。 文章目录 一、RAG分类二、评估方法三、未来方向 一、RAG分类 RAG分类:Navie RAG、Advanced RA…

美国大选后,用HMM模型做特斯拉股价波动解析

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话:本文主要探讨如何利用高斯隐马尔可夫模型(HMM)预测股票价格,我们将分步进行说明:包括数据准备、特征选择、训练 HMM 模型、最后…

VSCode(四)CMake调试

1. 工具准备 1.1 C环境插件 1.2 CMake插件 2. Cmake工程 2.1 创建项目文件夹 ex:CMAKE_TEST 2.2 创建CMake工程 (shift ctl P), 选择"CMAKE: Quick Start": 2.3 填写project name: (ex: test_cmake) 2.4 选择”Executable“ 项目文件内会自动…

从 HTML 到 CSS:开启网页样式之旅(七)—— CSS浮动

从 HTML 到 CSS:开启网页样式之旅(七)—— CSS浮动 前言一、浮动的简介1.没有浮动的代码和效果2.加入浮动的代码和效果 二、元素浮动后的特点1. 脱离文档流2.宽高特性:3.共用一行:4.margin 特性:5.区别于行…

微信小程序实现图片拖拽调换位置效果 -- 开箱即用

在编写类似发布朋友圈功能的功能时,需要实现图片的拖拽排序,删除图片等功能。 一、效果展示 **博主的小程序首页也采用了该示例代码,可以在威信中搜索:我的百宝工具箱 二、示例代码 1.1、在自己的小程序中创建组件 1.2、组件…

通过 FRP 实现 P2P 通信:控制端与被控制端配置指南

本文介绍了如何通过 FRP 实现 P2P 通信。FRP(Fast Reverse Proxy)是一款高效的内网穿透工具,能够帮助用户突破 NAT 和防火墙的限制,将内网服务暴露到公网。通过 P2P 通信方式,FRP 提供了更加高效、低延迟的网络传输方式…

php7.4安装pg扩展-contos7

今天接到一个需求,就是需要用thinkphp6链接pg(postgresql)数据库。废话不多说,直接上操作步骤 一、安装依赖 yum install -y sqlite-devel libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcurl-devel libjpeg libjpeg-dev…

CentOS7.X 安装RustDesk自建服务器实现远程桌面控制

参照文章CentOS安装RustDesk自建服务器中间总有几个位置出错,经实践做个记录防止遗忘 一 环境&工具准备 1.1 阿里云轻量服务器、Centos7系统、目前最高1.1.11版本rustdesk-server-linux-amd64.zip 1.2 阿里云轻量服务器–安全组–开放端口:TCP(21…

TCP Analysis Flags 之 TCP Spurious Retransmission

前言 默认情况下,Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态,并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时,会对每个 TCP 数据包进行一次分析,数据包按照它们在数据包列表中出现的顺序进行处理。可…

Java线程的interrupt中断、wait-notify/all(源码级分析)

实例方法: interrupt()方法是设置结束阻塞(sleep、wait等),并且设置中断标记true isInterrupted()判断当前是否中断 静态方法: Thread.interrupted():调用这个方法的线程中断标记位还原为false 那么好,既然上面的方法作用是清…

Burp Suite 实战指南:Proxy 捕获与修改流量、HTTP History 筛选与分析

声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…