226 votes

Pourquoi MYSQL LIMITE supérieure de décalage ralentir la requête vers le bas?

Scénario en bref: Une table avec plus de 16 millions de disques [2 go de taille]. La LIMITE supérieure de décalage avec la sélection, le ralentissement de la requête devient, lors de l'utilisation de la COMMANDE PAR *primary_key*

Donc

SELECT * FROM large ORDER BY `id`  LIMIT 0, 30 

prend beaucoup moins de

SELECT * FROM large ORDER BY `id` LIMIT 10000, 30 

Que seuls les ordres de 30 enregistrements et même eitherway. Il n'est donc pas la surcharge de l'ORDRE.
Maintenant, lors de l'extraction de la plus tard 30 lignes, il faut environ 180 secondes. Comment puis-je optimiser la simple requête?

286voto

Nikos Kyr Points 352

J'ai eu exactement le même problème moi-même. Compte tenu du fait que u besoin de recueillir une grande quantité de données et non pas un ensemble spécifique de 30 u 'll être probablement l'exécution d'une boucle et d'incrémenter le décalage par 30.

Donc ce que vous pouvez faire à la place est de:

1)Maintenez le dernier l'id d'un ensemble de données(30) (par exemple, lastId = 530)
2)Ajouter la condition "where id > lastId limite de 0,30"

Alors u peut toujours avoir un décalage de ZÉRO. Vous serez surpris par l'amélioration de la performance.

230voto

Quassnoi Points 191041

Il est normal que la hausse des décalages de ralentir la requête, la requête doit compter de la première OFFSET + LIMIT des dossiers (et de ne prendre que LIMIT d'entre eux). Plus cette valeur est élevée, plus l'exécution de la requête.

La requête ne peut pas aller droit à l' OFFSET parce que, d'abord, les enregistrements peuvent être de longueur différente, et, deuxièmement, il y a des écarts à partir des enregistrements supprimés. Il doit vérifier et compter chaque enregistrement sur son chemin.

En supposant que l' id est PRIMARY KEY d'un MyISAM tableau, vous pouvez l'accélérer en utilisant cette astuce:

SELECT  t.*
FROM    (
        SELECT  id
        FROM    mytable
        ORDER BY
                id
        LIMIT 10000, 30
        ) q
JOIN    mytable t
ON      t.id = q.id

Voir cet article:

21voto

Riedsio Points 4500

MySQL ne peut pas aller directement à la 10000th enregistrement (ou la 80000th octet comme votre suggérant) parce qu'il ne peut pas supposer qu'il est emballé/a ordonné comme ça (ou qu'il a des valeurs continues de 1 à 10000). Bien qu'il puisse en être ainsi dans la réalité, MySQL ne peut pas supposer qu'il n'y a pas de trous/écarts/supprimé id.

Donc, comme bobs noté, MySQL va récupérer de 10000 lignes (ou de parcourir à travers 10000th entrées de l'index sur id) avant de trouver la 30 à de retour.

EDIT : Pour illustrer mon point de vue

Notez que bien que

SELECT * FROM large ORDER BY id LIMIT 10000, 30 

serait lente(er),

SELECT * FROM large WHERE id >  10000 ORDER BY id LIMIT 30 

serait rapide(er), et renvoie le même résultat, à condition qu'il ne manque aucun ids (à savoir les lacunes).

5voto

bobs Points 12893

Le temps de deux requêtes est en train de récupérer les lignes de la table. Logiquement parlant, en LIMIT 0, 30 version, seulement 30 lignes doivent être récupérées. Dans l' LIMIT 10000, 30 version, 10000 lignes sont évalués et 30 lignes sont retournées. Il peut y avoir certains l'optimisation peut être faite mes données-processus de lecture, mais de considérer les éléments suivants:

Si vous aviez une clause where dans les requêtes? Le moteur doit retourner toutes les lignes éligibles, puis de trier les données, et enfin arriver le 30 lignes.

Considérer le cas où les lignes ne sont pas traitées dans l'ORDRE de la séquence. Toutes les lignes doivent être triés pour déterminer les lignes de retour.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X