Table des matières
Question
server层和存储引擎层
那LIMIT是什么鬼?
怎么办?
吐个槽
Maison base de données tutoriel mysql Analyse approfondie de l'instruction LIMIT dans MySQL

Analyse approfondie de l'instruction LIMIT dans MySQL

Oct 13, 2021 pm 07:02 PM
mysql

Cet article vous amènera à comprendre l'instruction LIMIT dans MySQL et à répondre à une question : le LIMIT de MySQL est-il si mauvais ? J'espère que cela aidera tout le monde !

Analyse approfondie de l'instruction LIMIT dans MySQL

Récemment, de nombreux amis ont posé aux enfants une question sur LIMIT dans le groupe Q&A. Permettez-moi de décrire brièvement cette question.

Question

Pour que l'histoire se déroule sans problème, nous devons d'abord avoir une table :

CREATE TABLE t (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    key1 VARCHAR(100),
    common_field VARCHAR(100),
    PRIMARY KEY (id),
    KEY idx_key1 (key1)
) Engine=InnoDB CHARSET=utf8;
Copier après la connexion

La table t contient 3 colonnes, la colonne id est la clé primaire et la colonne key1 est la colonne d'index secondaire. La table contient 10 000 enregistrements. [Recommandations associées : Tutoriel vidéo mysql]

Lorsque nous exécutons l'instruction suivante, nous utilisons l'index secondaire idx_key1 :

mysql>  EXPLAIN SELECT * FROM t ORDER BY key1 LIMIT 1;
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t     | NULL       | index | NULL          | idx_key1 | 303     | NULL |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
Copier après la connexion

C'est facile à comprendre, car dans l'index secondaire idx_key1, la colonne key1 est ordonnée. La requête consiste à récupérer le premier enregistrement trié par la colonne key1. Ensuite, MySQL n'a besoin que d'obtenir le premier enregistrement d'index secondaire de idx_key1, puis de revenir directement à la table pour obtenir l'enregistrement complet.

Mais si nous remplaçons LIMIT 1 dans l'instruction ci-dessus par LIMIT 5000, 1, alors nous devons effectuer une analyse complète de la table et un tri de fichiers. Le plan d'exécution est le suivant. : LIMIT 1换成LIMIT 5000, 1,则却需要进行全表扫描,并进行filesort,执行计划如下:

mysql>  EXPLAIN SELECT * FROM t ORDER BY key1 LIMIT 5000, 1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9966 |   100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)
Copier après la connexion

有的同学就很不理解了:LIMIT 5000, 1也可以使用二级索引idx_key1呀,我们可以先扫描到第5001条二级索引记录,对第5001条二级索引记录进行回表操作不就好了么,这样的代价肯定比全表扫描+filesort强呀。

很遗憾的告诉各位,由于MySQL实现上的缺陷,不会出现上述的理想情况,它只会笨笨的去执行全表扫描+filesort,下边我们唠叨一下到底是咋回事儿。

server层和存储引擎层

大家都知道,MySQL内部其实是分为server层和存储引擎层的:

  • server层负责处理一些通用的事情,诸如连接管理、SQL语法解析、分析执行计划之类的东西

  • 存储引擎层负责具体的数据存储,诸如数据是存储到文件上还是内存里,具体的存储格式是什么样的之类的。我们现在基本都使用InnoDB存储引擎,其他存储引擎使用的非常少了,所以我们也就不涉及其他存储引擎了。

MySQL中一条SQL语句的执行是通过server层和存储引擎层的多次交互才能得到最终结果的。比方说下边这个查询:

SELECT * FROM t WHERE key1 > &#39;a&#39; AND key1 < &#39;b&#39; AND common_field != &#39;a&#39;;
Copier après la connexion

server层会分析到上述语句可以使用下边两种方案执行:

  • 方案一:使用全表扫描

  • 方案二:使用二级索引idx_key1,此时需要扫描key1列值在('a', 'b')之间的全部二级索引记录,并且每条二级索引记录都需要进行回表操作。

server层会分析上述两个方案哪个成本更低,然后选取成本更低的那个方案作为执行计划。然后就调用存储引擎提供的接口来真正的执行查询了。

这里假设采用方案二,也就是使用二级索引idx_key1执行上述查询。那么server层和存储引擎层的对话可以如下所示:

Analyse approfondie de linstruction LIMIT dans MySQL

server层:“hey,麻烦去查查idx_key1二级索引的('a', 'b')区间的第一条记录,然后把回表后把完整的记录返给我哈”

InnoDB:“收到,这就去查”,然后InnoDB就通过idx_key1二级索引对应的B+树,快速定位到扫描区间('a', 'b')的第一条二级索引记录,然后进行回表,得到完整的聚簇索引记录返回给server层。

Analyse approfondie de linstruction LIMIT dans MySQL

server层收到完整的聚簇索引记录后,继续判断common_field!=&#39;a&#39;

SELECT * FROM t ORDER BY key1 LIMIT 5000, 1;
Copier après la connexion
Copier après la connexion

Certains étudiants ne comprennent pas : LIMIT 5000, 1 Vous pouvez également utiliser l'index secondaire idx_key1 Nous pouvons d'abord scanner le 5001ème enregistrement d'index secondaire, puis scanner le 5001ème enregistrement d'index secondaire. Ne serait-il pas agréable d'enregistrer et d'effectuer des opérations de retour de table ? Ce coût est nettement meilleur que l'analyse complète de la table + le tri de fichiers.

J'ai le regret de vous dire qu'en raison des défauts d'implémentation de MySQL, la situation idéale ci-dessus ne se produira pas. Il effectuera simplement une analyse complète de la table + un tri de fichiers bêtement.


couche serveur et couche moteur de stockage

Comme nous le savons tous, MySQL est en fait divisé en couche serveur et couche moteur de stockage :

  • 🎜server Le La couche moteur de stockage est responsable de la gestion de certaines choses courantes, telles que la gestion des connexions, l'analyse de la syntaxe SQL et l'analyse du plan d'exécution. La couche moteur de stockage est responsable du stockage des données spécifiques, par exemple si les données sont stockées dans des fichiers ou en mémoire. , quel est le format de stockage spécifique ? Nous utilisons essentiellement le moteur de stockage InnoDB maintenant, et les autres moteurs de stockage sont rarement utilisés, nous ne couvrirons donc pas les autres moteurs de stockage. 🎜
🎜L'exécution d'une instruction SQL dans MySQL obtient le résultat final grâce à de multiples interactions entre la couche serveur et la couche moteur de stockage. Par exemple, la requête ci-dessous : 🎜
SELECT * FROM t, (SELECT id FROM t ORDER BY key1 LIMIT 5000, 1) AS d
    WHERE t.id = d.id;
Copier après la connexion
Copier après la connexion
🎜La couche serveur analysera que l'instruction ci-dessus peut être exécutée en utilisant les deux options suivantes : 🎜
  • 🎜Option 1 : Utiliser l'analyse complète de la table🎜
  • 🎜Option 2 : utilisez l'index secondaire idx_key1. À ce stade, vous devez analyser tous les enregistrements d'index secondaire avec la valeur de la colonne key1 entre ('a', 'b'), et chaque enregistrement d'index secondaire doit être renvoyé au tableau. 🎜
🎜La couche serveur analysera laquelle des deux options ci-dessus est la moins coûteuse, puis sélectionnera l'option la moins coûteuse comme plan d'exécution. Ensuite, l'interface fournie par le moteur de stockage est appelée pour exécuter réellement la requête. 🎜🎜On suppose que l'option 2 est adoptée, c'est-à-dire que l'index secondaire idx_key1 est utilisé pour exécuter la requête ci-dessus. Ensuite, la conversation entre la couche serveur et la couche moteur de stockage peut être la suivante : 🎜🎜Analyse approfondie de linstruction LIMIT dans MySQL🎜🎜couche serveur : "Hé, veuillez vérifier le premier enregistrement dans l'intervalle ('a', 'b') de l'index secondaire idx_key1, puis renvoyez-le à la table. Renvoyez-moi l'enregistrement complet"🎜🎜InnoDB : "Reçu, vérifiez-le maintenant", puis InnoDB localise rapidement l'intervalle d'analyse ('a', 'b') via l'arborescence B+ correspondant à l'index secondaire idx_key1. Le premier enregistrement d'index secondaire est ensuite renvoyé à la table et l'enregistrement d'index cluster complet est renvoyé à la couche serveur. 🎜🎜Analyse approfondie de linstruction LIMIT dans MySQL🎜🎜serveur Une fois que la couche a reçu l'enregistrement d'index clusterisé complet, elle continue de déterminer si la condition common_field!='a' est vraie. Si elle n'est pas vraie, l'enregistrement est ignoré, sinon il est envoyé à. le client. Dites ensuite au moteur de stockage : "Veuillez me donner l'enregistrement suivant"🎜🎜🎜Conseils :🎜🎜Envoyer l'enregistrement au client ici revient en fait à l'envoyer au tampon du réseau local. La taille du tampon est contrôlée par net_buffer_length. Taille de 16 Ko. Attendez que le tampon soit plein avant d'envoyer le paquet réseau au client. 🎜🎜🎜InnoDB : "Reçu, vérifiez maintenant". InnoDB trouve l'enregistrement d'index secondaire suivant dans l'intervalle ('a', 'b') de idx_key1 en fonction de l'attribut next_record de l'enregistrement, puis effectue une opération de retour de table et renvoie l'enregistrement d'index cluster complet à la couche serveur. 🎜

小贴士:

不论是聚簇索引记录还是二级索引记录,都包含一个称作next_record的属性,各个记录根据next_record连成了一个链表,并且链表中的记录是按照键值排序的(对于聚簇索引来说,键值指的是主键的值,对于二级索引记录来说,键值指的是二级索引列的值)。

Analyse approfondie de linstruction LIMIT dans MySQL

server层收到完整的聚簇索引记录后,继续判断common_field!=&#39;a&#39;条件是否成立,如果不成立则舍弃该记录,否则将该记录发送到客户端。然后对存储引擎说:“请把下一条记录给我哈”

... 然后就不停的重复上述过程。

直到:

Analyse approfondie de linstruction LIMIT dans MySQL

也就是直到InnoDB发现根据二级索引记录的next_record获取到的下一条二级索引记录不在('a', 'b')区间中,就跟server层说:“好了,('a', 'b')区间没有下一条记录了”

server层收到InnoDB说的没有下一条记录的消息,就结束查询。

现在大家就知道了server层和存储引擎层的基本交互过程了。

那LIMIT是什么鬼?

说出来大家可能有点儿惊讶,MySQL是在server层准备向客户端发送记录的时候才会去处理LIMIT子句中的内容。拿下边这个语句举例子:

SELECT * FROM t ORDER BY key1 LIMIT 5000, 1;
Copier après la connexion
Copier après la connexion

如果使用idx_key1执行上述查询,那么MySQL会这样处理:

  • server层向InnoDB要第1条记录,InnoDB从idx_key1中获取到第一条二级索引记录,然后进行回表操作得到完整的聚簇索引记录,然后返回给server层。server层准备将其发送给客户端,此时发现还有个LIMIT 5000, 1的要求,意味着符合条件的记录中的第5001条才可以真正发送给客户端,所以在这里先做个统计,我们假设server层维护了一个称作limit_count的变量用于统计已经跳过了多少条记录,此时就应该将limit_count设置为1。

  • server层再向InnoDB要下一条记录,InnoDB再根据二级索引记录的next_record属性找到下一条二级索引记录,再次进行回表得到完整的聚簇索引记录返回给server层。server层在将其发送给客户端的时候发现limit_count才是1,所以就放弃发送到客户端的操作,将limit_count加1,此时limit_count变为了2。

  • ... 重复上述操作

  • 直到limit_count等于5000的时候,server层才会真正的将InnoDB返回的完整聚簇索引记录发送给客户端。

从上述过程中我们可以看到,由于MySQL中是在实际向客户端发送记录前才会去判断LIMIT子句是否符合要求,所以如果使用二级索引执行上述查询的话,意味着要进行5001次回表操作。server层在进行执行计划分析的时候会觉得执行这么多次回表的成本太大了,还不如直接全表扫描+filesort快呢,所以就选择了后者执行查询。

怎么办?

由于MySQL实现LIMIT子句的局限性,在处理诸如LIMIT 5000, 1这样的语句时就无法通过使用二级索引来加快查询速度了么?其实也不是,只要把上述语句改写成:

SELECT * FROM t, (SELECT id FROM t ORDER BY key1 LIMIT 5000, 1) AS d
    WHERE t.id = d.id;
Copier après la connexion
Copier après la connexion

这样,SELECT id FROM t ORDER BY key1 LIMIT 5000, 1作为一个子查询单独存在,由于该子查询的查询列表只有一个id列,MySQL可以通过仅扫描二级索引idx_key1执行该子查询,然后再根据子查询中获得到的主键值去表t中进行查找。

这样就省去了前5000条记录的回表操作,从而大大提升了查询效率!

吐个槽

设计MySQL的大叔啥时候能改改LIMIT子句的这种超笨的实现呢?还得用户手动想欺骗优化器的方案才能提升查询效率~

更多编程相关知识,请访问:编程视频!!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment ouvrir phpmyadmin Comment ouvrir phpmyadmin Apr 10, 2025 pm 10:51 PM

Vous pouvez ouvrir PHPMYADMIN via les étapes suivantes: 1. Connectez-vous au panneau de configuration du site Web; 2. Trouvez et cliquez sur l'icône PHPMYADMIN; 3. Entrez les informations d'identification MySQL; 4. Cliquez sur "Connexion".

MySQL: une introduction à la base de données la plus populaire au monde MySQL: une introduction à la base de données la plus populaire au monde Apr 12, 2025 am 12:18 AM

MySQL est un système de gestion de la base de données relationnel open source, principalement utilisé pour stocker et récupérer les données rapidement et de manière fiable. Son principe de travail comprend les demandes des clients, la résolution de requête, l'exécution des requêtes et les résultats de retour. Des exemples d'utilisation comprennent la création de tables, l'insertion et la question des données et les fonctionnalités avancées telles que les opérations de jointure. Les erreurs communes impliquent la syntaxe SQL, les types de données et les autorisations, et les suggestions d'optimisation incluent l'utilisation d'index, les requêtes optimisées et la partition de tables.

Comment utiliser un seul fileté redis Comment utiliser un seul fileté redis Apr 10, 2025 pm 07:12 PM

Redis utilise une architecture filetée unique pour fournir des performances élevées, une simplicité et une cohérence. Il utilise le multiplexage d'E / S, les boucles d'événements, les E / S non bloquantes et la mémoire partagée pour améliorer la concurrence, mais avec des limites de limitations de concurrence, un point d'échec unique et inadapté aux charges de travail à forte intensité d'écriture.

Place de MySQL: bases de données et programmation Place de MySQL: bases de données et programmation Apr 13, 2025 am 12:18 AM

La position de MySQL dans les bases de données et la programmation est très importante. Il s'agit d'un système de gestion de base de données relationnel open source qui est largement utilisé dans divers scénarios d'application. 1) MySQL fournit des fonctions efficaces de stockage de données, d'organisation et de récupération, en prenant en charge les systèmes Web, mobiles et de niveau d'entreprise. 2) Il utilise une architecture client-serveur, prend en charge plusieurs moteurs de stockage et optimisation d'index. 3) Les usages de base incluent la création de tables et l'insertion de données, et les usages avancés impliquent des jointures multiples et des requêtes complexes. 4) Des questions fréquemment posées telles que les erreurs de syntaxe SQL et les problèmes de performances peuvent être déboguées via la commande Explication et le journal de requête lente. 5) Les méthodes d'optimisation des performances comprennent l'utilisation rationnelle des indices, la requête optimisée et l'utilisation des caches. Les meilleures pratiques incluent l'utilisation des transactions et des acteurs préparés

Pourquoi utiliser MySQL? Avantages et avantages Pourquoi utiliser MySQL? Avantages et avantages Apr 12, 2025 am 12:17 AM

MySQL est choisi pour ses performances, sa fiabilité, sa facilité d'utilisation et son soutien communautaire. 1.MySQL fournit des fonctions de stockage et de récupération de données efficaces, prenant en charge plusieurs types de données et opérations de requête avancées. 2. Adoptez l'architecture client-serveur et plusieurs moteurs de stockage pour prendre en charge l'optimisation des transactions et des requêtes. 3. Facile à utiliser, prend en charge une variété de systèmes d'exploitation et de langages de programmation. 4. Avoir un solide soutien communautaire et fournir des ressources et des solutions riches.

Comment se connecter à la base de données d'Apache Comment se connecter à la base de données d'Apache Apr 13, 2025 pm 01:03 PM

Apache se connecte à une base de données nécessite les étapes suivantes: Installez le pilote de base de données. Configurez le fichier web.xml pour créer un pool de connexion. Créez une source de données JDBC et spécifiez les paramètres de connexion. Utilisez l'API JDBC pour accéder à la base de données à partir du code Java, y compris l'obtention de connexions, la création d'instructions, les paramètres de liaison, l'exécution de requêtes ou de mises à jour et de traitement des résultats.

CentOS installe MySQL CentOS installe MySQL Apr 14, 2025 pm 08:09 PM

L'installation de MySQL sur CENTOS implique les étapes suivantes: Ajout de la source MySQL YUM appropriée. Exécutez la commande YUM Install MySQL-Server pour installer le serveur MySQL. Utilisez la commande mysql_secure_installation pour créer des paramètres de sécurité, tels que la définition du mot de passe de l'utilisateur racine. Personnalisez le fichier de configuration MySQL selon les besoins. Écoutez les paramètres MySQL et optimisez les bases de données pour les performances.

Comment démarrer MySQL par Docker Comment démarrer MySQL par Docker Apr 15, 2025 pm 12:09 PM

Le processus de démarrage de MySQL dans Docker se compose des étapes suivantes: Tirez l'image MySQL pour créer et démarrer le conteneur, définir le mot de passe de l'utilisateur racine et mapper la connexion de vérification du port Créez la base de données et l'utilisateur accorde toutes les autorisations sur la base de données

See all articles