2010-07-27 14 views
0

J'ai un fichier qui passe par un grand ensemble de données et divise les lignes d'une manière paginée. L'ensemble de données contient environ 210k lignes, ce qui n'est même pas beaucoup, il passera à 3Mil + dans quelques semaines, mais c'est déjà lent.Obtenir le nombre total d'enregistrements de la table mysql - trop lent

J'ai une première requête qui obtient le nombre total d'articles dans la base de données pour un particulier où la combinaison de la clause, le plus basique ressemble à ceci:

SELECT count(v_id) as num_items FROM versions 
WHERE v_status = 1 

Il faut 0,9 secondes pour exécuter.

La 2ème requête est une requête LIMIT qui obtient les données réelles pour cette page. Cette requête est vraiment rapide. (moins de 0,001 s).

SELECT 
     v_id, 
     v_title, 
     v_desc 
    FROM versions 
    WHERE v_status = 1 
    ORDER BY v_dateadded DESC 
    LIMIT 0, 25 

Il y a un index sur v_status, v_dateadded

J'utilise php. Je cache le résultat dans memcace, donc les requêtes suivantes sont vraiment rapides, mais la première requête est laggy. Surtout quand je lance une recherche en texte intégral, cela commence à prendre 2-3 secondes pour les 2 requêtes.

+0

Pouvez-vous nous montrer la sortie des versions «DESCRIBE versions» ou «SHOW CREATE TABLE» s'il vous plaît? – Charles

+0

Est-ce que 'SELECT COUNT (*) ...' est plus rapide? –

+1

... aussi - y a-t-il un index sur 'v_status'? –

Répondre

2

Je ne pense pas que ce soit correct, mais essayez de le faire compter (*), je pense que le compte (x) doit passer par chaque ligne et ne compter que ceux qui n'ont pas de valeur nulle (donc il doit passer par toutes les lignes)

Étant donné que v_id est une clé primaire, il ne doit pas avoir de valeurs nulles, alors essayez cOUNT (*) à la place ...

Mais je ne pense pas que cela vous aidera puisque vous avez une clause where.

+0

C'était juste. compte (*) prend 0.1 secondes! –

0

Vous ne savez pas si c'est la même chose pour MySQL, mais dans MS SQL Server, COUNT (*) est presque toujours plus rapide que COUNT (colonne). L'analyseur détermine la colonne la plus rapide à compter et l'utilise.

0

Exécutez un plan d'explication pour voir comment l'optimiseur exécute vos requêtes.

Cela vous dira probablement ce qu'Andrea Rehm vous a dit: vous voudrez ajouter des index qui couvrent vos clauses where.

0

EDIT: Pour moi FOUND_ROWS() a été le meilleur moyen de le faire:

SELECT 
     SQL_CALC_FOUND_ROWS 
     v_id, 
     v_title, 
     v_desc 
    FROM versions 
    WHERE v_status = 1 
    ORDER BY v_dateadded DESC 
    LIMIT 0, 25; 

Puis dans une requête secondaire ne vient:

SELECT FOUND_ROWS(); 

Si vous produisez vous PHP faire :

$totalnumber = mysql_result(mysql_query($secondquery)),0,0); 

J'ai essayé auparavant la même chose que OP, mettre COUNT (column) sur la première requête, mais il a fallu environ trois fois plus de temps que la requête WHERE et ORDERBY la plus lente que je pouvais faire (avec un ensemble LIMIT). J'ai essayé de passer à COUNT (*) et ça s'est beaucoup amélioré. Mais les résultats dans mon cas étaient encore meilleurs en utilisant FOUND_ROWS() de MySQL;

Je teste en PHP avec microtime et répéter la requête. Dans le cas d'OP, s'il a couru COUNT (*), je pense qu'il va économiser du temps, mais ce n'est pas le moyen le plus rapide de le faire. J'ai effectué quelques tests sur COUNT (*) VS. FOUND_ROWS() et FOUND_ROWS() sont un peu plus rapides.L'utilisation de FOUND_ROWS() était presque deux fois plus rapide dans mon cas.

J'ai d'abord commencé à faire EXPLAIN sur la requête COUNT (*). Dans le cas d'OP, vous verrez que MySQL vérifie toujours un total de 210k lignes dans la première requête. Il vérifie toutes les lignes avant même de démarrer la requête LIMIT et ne semble pas bénéficier d'avantages en termes de performances. Si vous exécutez EXPLAIN sur la requête LIMIT, il vérifie probablement moins de 100 lignes car vous avez limité les résultats à 25. Mais cela se chevauche encore et il y aura des cas où vous ne pouvez pas vous le permettre ou au Au moins, vous devriez toujours comparer les performances avec FOUND_ROWS(). Je pensais que cela pourrait seulement gagner du temps sur les grandes demandes de LIMIT, mais quand j'exécute EXPLAIN sur ma requête LIMIT, elle vérifiait seulement 25 lignes pour obtenir 15 valeurs. Cependant, il y avait encore une différence très sensible dans le temps de requête - en moyenne, je suis passé de 0,25 à 0,14 secondes et j'ai obtenu les mêmes résultats.