MySQL Must Know 11 : Index - Améliorer la vitesse des requêtes

La lecture est compilée à partir de "MySQL Must Know and Know" - Zhu Xiaofeng . Pour plus de détails, veuillez vous connecter à la colonne d'achat sur le site officiel de Geek Time .


L'index dans MySQL est équivalent au catalogue de récupération de la bibliothèque, qui est une structure de stockage qui aide le système MySQL à récupérer rapidement les données.

Selon les conditions de requête dans l'index, récupérez la valeur du champ d'index, puis localisez rapidement la position de l'enregistrement de données, de sorte qu'il n'est pas nécessaire de parcourir l'intégralité de la table de données.

Plus il y a de champs dans la table de données, plus il y a d'enregistrements de données dans la table, plus l'amélioration de la vitesse est évidente .

Ma préparation des données de test :

create table demo.trans 
(
itemnumber int,
quantity text,
price text,
transdate datetime,
cashiernumber int,
branchnumber int
);

insert into demo.trans (itemnumber, quantity, price, transdate, cashiernumber, branchnumber) values (1, 1, 1, '2022-03-15', 1, 1);
-- ......
mysql> select * from demo.trans;
+------------+----------+-------+---------------------+---------------+--------------+
| itemnumber | quantity | price | transdate           | cashiernumber | branchnumber |
+------------+----------+-------+---------------------+---------------+--------------+
|          1 | 1        | 1     | 2022-03-15 00:00:00 |             1 |            1 |
|          2 | 2        | 2     | 2022-03-15 00:00:00 |             2 |            1 |
|          3 | 3        | 3     | 2022-03-15 00:00:00 |             3 |            1 |
|          1 | 1        | 1     | 2022-03-15 00:00:00 |             1 |            2 |
|          2 | 2        | 2     | 2022-03-15 00:00:00 |             2 |            2 |
|          3 | 3        | 3     | 2022-03-15 00:00:00 |             3 |            2 |
|          1 | 1        | 1     | 2022-03-16 00:00:00 |             1 |            1 |
|          2 | 2        | 2     | 2022-03-16 00:00:00 |             2 |            1 |
|          3 | 3        | 3     | 2022-03-16 00:00:00 |             3 |            1 |
|          1 | 1        | 1     | 2022-03-17 00:00:00 |             1 |            2 |
|          2 | 2        | 2     | 2022-03-17 00:00:00 |             2 |            2 |
|          3 | 3        | 3     | 2022-03-17 00:00:00 |             3 |            2 |
+------------+----------+-------+---------------------+---------------+--------------+
12 rows in set (0.00 sec)

Vérifiez les ventes du produit dont le numéro de produit est 1 au jour du 2022-03-17 :

mysql> select quantity, price, transdate from demo.trans where transdate = '2022-03-17' and itemnumber = 1;
+----------+-------+---------------------+
| quantity | price | transdate           |
+----------+-------+---------------------+
| 1        | 1     | 2022-03-17 00:00:00 |
+----------+-------+---------------------+
1 row in set (0.00 sec)  -- 我这边测试数据太少了,体现不出来查询时间快慢。。。

Trouvez un moyen de voir les millisecondes :

set profiling=1;     -- 置为1表示开启,置为0表示关闭
-- 执行其他 sql 命令
show profiles;  -- 查看上一条命令的耗时

Après la configuration, exécutez d'abord la requête, puis créez l'index, et enfin interrogez à nouveau.


index de champ unique

MySQL prend en charge les index à champ unique et les index composites, et les index à champ unique sont plus couramment utilisés.

Créer un index à champ unique

Il existe généralement trois façons de créer un index à champ unique :

  1. Il est relativement simple de créer directement des index pour des tables existantes via l'instruction CREATE ;
  2. Créer des index lors de la création de tables ;
  3. Créer un index en modifiant la table

Créer un index directement dans la table de données

create index 索引名 on table 表名(字段);
-- create index index_cashiernumber on demo.trans (cashiernumber);

Créer un index lors de la création de la table

create table 表名
(
字段 数据类型,
{ index | key} 索引名(字段)
)

Créer un index lors de la modification d'une table

alter talbe 表名 add { index | key } 索引名(字段);
--  alter table demo.trans add index index_itemnumber (itemnumber);

De plus, lors de la définition d'une contrainte de clé primaire ou d'une contrainte unique sur une table, MySQL créera automatiquement un index de clé primaire ou un index unique.

Exemple:

Créez un index pour la table demo.trans, interrogez une fois avant et après :

select quantity, price, transdate from demo.trans where transdate = '2022-03-17' and itemnumber = 3;  -- 没有索引

create index index_trans on demo.trans(transdate);  -- 加索引

select quantity, price, transdate from demo.trans where transdate = '2022-03-17' and itemnumber = 3;  -- 通过索引查询

Du fait qu'elle prend du temps, on peut voir que la requête indexée est plus rapide :

mysql> show profiles;
+----------+------------+-------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                                                       |
+----------+------------+-------------------------------------------------------------------------------------------------------------+
|       10 | 0.01542675 | select quantity, price, transdate from demo.trans where transdate = '2022-03-17' and itemnumber = 3         |
|       11 | 0.96726050 | create index index_trans on demo.trans(transdate)                                                           |
|       12 | 0.00101600 | select quantity, price, transdate from demo.trans where transdate = '2022-03-17' and itemnumber = 3         |
+----------+------------+-------------------------------------------------------------------------------------------------------------+

Après avoir ajouté l'index, c'est plus de 15 fois plus rapide que sans index. Un écart aussi important montre que l'index est vraiment utile pour améliorer la vitesse de requête.


Fonctionnement des index à champ unique

Utilisez le mot clé EXPLAIN dans MySQL pour comprendre le rôle des index.

Le mot-clé EXPLAIN peut afficher les détails d'exécution de l'instruction SQL, y compris l'ordre dans lequel les tables sont chargées, la manière dont les tables sont connectées et l'utilisation des index.

mysql> explain select quantity, price, transdate from demo.trans where transdate = '2022-03-17' and itemnumber = 3;
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key         | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | trans | NULL       | ref  | index_trans   | index_trans | 6       | const |    3 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------------+
  • type=ref : Indique que la colonne de condition de recherche utilise un index et n'est pas une clé primaire et unique
  • rows=3 : Indique le nombre d'enregistrements à lire
  • possible_keys=index_trans : indique que l'index pouvant être sélectionné est index_trans
  • key=index_trans : Indique que l'index effectivement sélectionné est index_trans
  • extra=Using where : filtré par la condition WHERE ;
    par exemple, extra=Using index condition;Using where;Using MRR : les informations ici expliquent plus en détail les détails d'exécution de l'instruction SQL, y compris 3 couches de signification : la première L'index est utilisé pendant l'exécution, le second est filtré par la condition WHERE pendant l'exécution, et le troisième est la stratégie d'utilisation de lectures séquentielles sur disque.

Sélectionnez le champ d'index

Utilisez d'autres champs pour l'indexation :

create index index_trans_itemnumber on demo.trans(itemnumber);
mysql> explain select quantity, price, transdate from demo.trans where transdate = '2022-03-17' and itemnumber = 3;
+----+-------------+-------+------------+------+------------------------------------+-------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys                      | key         | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+------+------------------------------------+-------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | trans | NULL       | ref  | index_trans,index_trans_itemnumber | index_trans | 6       | const |    3 |    33.33 | Using where |
+----+-------------+-------+------------+------+------------------------------------+-------------+---------+-------+------+----------+-------------

"possible_keys= index_trans, index_trans_itemnumber", c'est-à-dire que MySQL pense qu'il y a bien 2 index qui peuvent être sélectionnés, l'un est l'index index_trans créé avec le champ transdate, et l'autre est l'index_trans_itemnumber créé avec le champ itemnumber. key= index_trans, indiquant que l'index que MySQL choisit réellement d'utiliser est l'index index_trans créé par le champ transdate.

Par conséquent, lors de la sélection des champs d'index, sélectionnez les champs qui sont souvent utilisés comme conditions de filtre . Ce n'est qu'ainsi que le rôle de l'index peut être joué et que l'efficacité de la récupération peut être améliorée.


index composé

Dans le travail réel, on rencontre parfois une table de données plus complexe, qui comprend de nombreux champs, et il est souvent nécessaire de filtrer les données à travers différents champs, en particulier lorsque la table de données contient plusieurs niveaux d'informations. Par exemple, le compteur de flux de vente contient trois niveaux d'informations : informations sur le magasin, informations sur la caisse enregistreuse et informations sur le produit. Un magasin correspond à plusieurs caisses enregistreuses dans le magasin, et chaque caisse enregistreuse correspond à plusieurs produits vendus à partir de cette caisse enregistreuse. Ces niveaux d'informations sont souvent utilisés comme conditions de filtre pour la requête. À l'heure actuelle, les index à champ unique ne sont souvent pas faciles à exercer l'effet maximal des index, et des index composites peuvent être utilisés.

Effet d'index unique :

mysql> select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3;
+------------+
| itemnumber |
+------------+
|          3 |
|          3 |
+------------+

mysql> explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | trans | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   12 |     8.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

-- 原来所有索引被删除掉,重新创建如下3个单字段索引:
mysql> create index i_itemnumber on demo.trans (itemnumber);
mysql> create index i_cashiernumber on demo.trans (cashiernumber);
mysql> create index i_branch on demo.trans (branchnumber);

mysql> select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3;
+------------+
| itemnumber |
+------------+
|          3 |
|          3 |
+------------+

mysql> explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3;
+----+-------------+-------+------------+------+---------------------------------------+--------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys                         | key          | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------------------------------+--------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | trans | NULL       | ref  | i_itemnumber,i_cashiernumber,i_branch | i_itemnumber | 5       | const |    4 |    16.67 | Using where |
+----+-------------+-------+------------+------+---------------------------------------+--------------+---------+-------+------+----------+-------------+

mysql> show profiles;
+----------+------------+-----------------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                                                                 |
+----------+------------+-----------------------------------------------------------------------------------------------------------------------+
|      117 | 0.00958000 | select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3                           |
|      118 | 0.00031150 | explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3                   |

|      122 | 0.00045350 | select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3                           |
|      123 | 0.00055550 | explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3                   |
+----------+------------+-----------------------------------------------------------------------------------------------------------------------+

MySQL a 3 index disponibles, i_branchnumber créé avec branchnumber, i_cashiernumber créé avec cashiernumber et i_itemnumber créé avec itemnumber. MySQL choisit toujours i_itemnumber, et le nombre réel d'enregistrements filtrés est de 5.

L'optimiseur dispose désormais de 3 index disponibles, à savoir l'index du numéro de marchandise, l'index du numéro de magasin et l'index du numéro de caisse enregistreuse. L'optimiseur trouve que l'index de numéro d'article recherche en fait le plus petit nombre d'enregistrements, il choisit donc cet index en dernier.

S'il existe plusieurs index et que les champs de ces index apparaissent dans la requête en tant que champs de filtre en même temps, MySQL choisira d'utiliser l'index optimal pour effectuer l'opération de requête.

Ces champs de filtre peuvent-ils fonctionner en même temps ? C'est là que les index composites sont utilisés. Un index composite est un index qui contient plusieurs champs. MySQL prend en charge les index composites comprenant jusqu'à 16 champs.


Créer un index composite

La structure grammaticale de la création d'un index composite est la même que celle de la création d'un index à champ unique. La différence est que, par rapport à un index à champ unique, un index composite utilise plusieurs champs.

Créer un index directement dans la table de données

create index 索引名 on table 表名(字段1, 字段2, ...);

Créer un index lors de la création de la table

create table 表名
(
字段 数据类型,.
{ index | key } 索引名(字段1,字段2...)
)

Créer un index lors de la modification d'une table

alter table 表名 add { index | key } 索引名 (字段1, 字段2, ...);

Exemple:

Pour le scénario de requête tout à l'heure, vous pouvez créer un index composite pour jouer le rôle de filtrage de plusieurs champs. Plus précisément, créez un index combiné composé de trois champs branchnumber, cashiernumber et itemnumber :

mysql> create index i_branch_cashier_item ON demo.trans (branchnumber,cashiernumber,itemnumber);

mysql> select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3;
+------------+
| itemnumber |
+------------+
|          3 |
|          3 |
+------------+

mysql> explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3;
+----+-------------+-------+------------+------+-------------------------------------------------------------+-----------------------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys                                               | key                   | key_len | ref               | rows | filtered | Extra       |
+----+-------------+-------+------------+------+-------------------------------------------------------------+-----------------------+---------+-------------------+------+----------+-------------+
|  1 | SIMPLE      | trans | NULL       | ref  | i_itemnumber,i_cashiernumber,i_branch,i_branch_cashier_item | i_branch_cashier_item | 15      | const,const,const |    2 |   100.00 | Using index |
+----+-------------+-------+------------+------+-------------------------------------------------------------+-----------------------+---------+-------------------+------+----------+-------------+
mysql> show profiles;
+----------+------------+-----------------------------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                                               |
+----------+------------+-----------------------------------------------------------------------------------------------------+                                  
|      122 | 0.00045350 | select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3         |
|      123 | 0.00055550 | explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3 |

|      124 | 0.48831800 | create index i_branch_cashier_item ON demo.trans (branchnumber,cashiernumber,itemnumber)            |

|      125 | 0.00829500 | select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3         |
|      126 | 0.00029475 | explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3 |
|      127 | 0.00042275 | select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3         |  -- 多执行了一次看看
|      128 | 0.00031475 | explain select itemnumber from demo.trans where branchnumber=2 and cashiernumber=3 and itemnumber=3 |
+----------+------------+-----------------------------------------------------------------------------------------------------+

Pour cette requête, MySQL peut utiliser 4 index : i_trans_itemnumber, i_trans_branchnumber, i_trans_cashiernumber, i_branch_cashier_item, et il n'y a que 2 lignes.


Le principe de l'indice composite

Les champs multiples de l'index composite sont ordonnés et suivent le principe de l'alignement à gauche . Par exemple, l'index composite créé est trié par numéro de succursale, numéro de caissier et numéro d'article. Par conséquent, les conditions de filtrage doivent également suivre le principe de gauche à droite.S'il est interrompu, alors les conditions derrière le point d'arrêt ne peuvent pas utiliser l'index.

  • Si la condition est changée en "cashiernumber = 1 AND itemnumber = 1", le champ branchnumber le plus à gauche n'est pas inclus dans la condition et est interrompu, donc cette condition ne peut pas du tout utiliser un index composite

  • Si le filtre est une plage, s'il n'y a aucun moyen de localiser avec précision, cela équivaut également à une interruption. Par exemple, la condition "branchnumber>1 AND cashiernumber=3 AND itemnumber=3" ne peut être utilisée que pour la partie de branchnumber>1 dans l'index combiné, et les index suivants ne seront pas utilisés. Pour le moment, MySQL ne choisissez l'index combiné, mais L'index normal i_itemnumber créé avec itemnumber est sélectionné.

    mysql> explain select itemnumber from demo.trans where branchnumber>1 and cashiernumber=3 and itemnumber=3;
    +----+-------------+-------+------------+------+-------------------------------------------------------------+--------------+---------+-------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys                                               | key          | key_len | ref   | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+-------------------------------------------------------------+--------------+---------+-------+------+----------+-------------+
    |  1 | SIMPLE      | trans | NULL       | ref  | i_itemnumber,i_cashiernumber,i_branch,i_branch_cashier_item | i_itemnumber | 5       | const |    4 |    16.67 | Using where |
    

Si vous n'utilisez qu'une partie de l'index composite, l'effet n'est pas aussi bon que l'index à champ unique.


résumé

L'indexation peut améliorer considérablement la vitesse d'interrogation des données, plus il y a de données contenues dans la table de données, plus l'effet est important.

Les champs qui sont souvent utilisés comme conditions de filtre doivent être sélectionnés pour créer des index, de sorte que la portée de la lecture réelle des données dans la table de données puisse être réduite via l'index et que les avantages de l'index puissent être mis en jeu.

S'il existe plusieurs champs filtrés et qu'ils apparaissent souvent ensemble, plusieurs champs peuvent également être utilisés pour créer un index composite.

Supprimez l'index :

drop index 索引名 on 表名;

Certains index ne peuvent pas être supprimés de cette manière, comme l'index de clé primaire, vous devez modifier la table pour supprimer l'index :

alter table 表名 drop primary key;

L'indexation peut améliorer l'efficacité des requêtes, mais la création d'un index a également des coûts. Il y a deux aspects principaux, l'un est la surcharge de l'espace de stockage et l'autre est la surcharge des opérations de données :

  • La surcharge de l'espace de stockage signifie que l'index doit occuper un espace de stockage séparé
  • La surcharge des opérations de données signifie qu'une fois que la table de données change, qu'il s'agisse d'insérer une nouvelle donnée, de supprimer une ancienne donnée ou même de modifier les données, si le champ d'index est impliqué, l'index lui-même doit être modifié. pour s'assurer que l'index peut pointer vers le bon enregistrement.

Par conséquent, plus il y a d'index, mieux c'est, la création d'index entraîne une surcharge de stockage et une surcharge d'exploitation, qui doivent être prises en compte de manière globale.

Guess you like

Origin blog.csdn.net/qq_31362767/article/details/123602732