y a-t-il quelque chose de plus rapide que le fait de compter & # 8221; pour les grandes tables?

StackOverflow https://stackoverflow.com/questions/818868

Question

Voici ma requête:

select word_id, count(sentence_id) 
from sentence_word 
group by word_id 
having count(sentence_id) > 100;

La table phraseword contient 3 champs, wordid, phraseid et un identifiant de clé primaire. Il a 350k + lignes. Cette requête prend 85 secondes et je me demande (en espérant, en priant?) Qu'il existe un moyen plus rapide de trouver tous les wordids qui ont plus de 100 phraseids.

J'ai essayé d'extraire la partie "compte choisi", et de ne faire qu'avoir un compte (1), mais aucun ne l'accélère.

J'apprécierais toute aide que vous pourriez apporter. Merci!

Était-ce utile?

La solution

  

ayant le compte (phrase_id) > 100;

Cela pose un problème ... Soit la table contient des paires mot / phrase en double, soit elle ne le fait pas.

S'il existe des paires mot / phrase en double, utilisez ce code pour obtenir la réponse correcte:

HAVING COUNT(DISTINCT Sentence_ID) > 100

Si la table ne contient pas de paires mot / phrase en double, vous ne devez pas compter phrase_ids, vous devez simplement compter les lignes.

HAVING COUNT(*) > 100

Dans ce cas, vous pouvez créer un index sur mot_id uniquement , pour des performances optimales.

Autres conseils

Si vous n'en avez pas déjà un, créez un index composite sur sentence_id, word_id.

Si cette requête est souvent effectuée et que la table est rarement mise à jour, vous pouvez conserver une table auxiliaire avec les identifiants de mots et le nombre de phrases correspondantes - il est difficile de penser à une optimisation supplémentaire au-delà!

Votre requête est correcte, mais elle nécessite un peu d'aide (index) pour obtenir des résultats plus rapides.

Je n'ai pas mes ressources sous la main (ni accès à SQL), mais je vais essayer de vous aider de mémoire.

Conceptuellement, le seul moyen de répondre à cette requête est de compter tous les enregistrements partageant le même mot_id. Cela signifie que le moteur de requête a besoin d'un moyen rapide pour trouver ces enregistrements. Sans index sur word_id, la base de données ne peut que parcourir la table, enregistrement par enregistrement, et conserver les totaux cumulés de chaque mot_id distinct détecté. Cela nécessiterait généralement une table temporaire et aucun résultat ne peut être envoyé avant que toute la table ne soit analysée. Pas bien.

Avec un index sur word_id, il doit toujours passer par la table, donc vous pensez bien que cela n’aiderait pas beaucoup. Cependant, le moteur SQL peut maintenant calculer le nombre pour chaque mot_id sans attendre la fin de la table: il peut envoyer la ligne et le nombre pour cette valeur de mot_id (s'il passe votre clause where ). , ou élimine la ligne (si ce n'est pas le cas); cela entraînera une charge de mémoire plus faible sur le serveur, éventuellement des réponses partielles, et la table temporaire n'est plus nécessaire. Un deuxième aspect est le parallélisme; avec un index sur word_id, SQL peut fractionner le travail en morceaux et utiliser des cœurs de processeur distincts pour exécuter la requête en parallèle (en fonction des capacités matérielles et de la charge de travail existante).

Cela pourrait suffire à aider votre requête; mais vous devrez essayer de voir:

CREATE INDEX someindexname ON sentence_word (word_id)

(syntaxe T-SQL; vous n'avez pas spécifié le produit SQL que vous utilisez)

Si cela ne suffit pas (ou n’aide en rien), il existe deux autres solutions.

Premièrement, SQL vous permet de pré-calculer COUNT (*) à l’aide de vues indexées et d’autres mécanismes. Je n'ai pas les détails sous la main (et je ne le fais pas souvent). Si vos données ne changent pas souvent, cela vous donnerait des résultats plus rapides mais avec un coût en complexité et un peu de stockage.

Vous pouvez également envisager de stocker les résultats de la requête dans une table séparée. Cela n’est pratique que si les données ne changent jamais ou selon un calendrier précis (par exemple, lors d’une actualisation des données à 2 heures du matin), ou si cela change très peu et que vous pouvez vivre avec des résultats imparfaits pendant quelques heures (vous devrait planifier un rafraîchissement périodique des données); c'est l'équivalent moral de l'entrepôt de données d'un pauvre.

La meilleure façon de déterminer avec certitude ce qui fonctionne pour vous consiste à exécuter la requête et à consulter le plan de requête avec et sans certains index candidats comme celui ci-dessus.

Il existe, de manière surprenante, un moyen encore plus rapide de réaliser cela sur de grands ensembles de données:

SELECT totals.word_id, totals.num 
  FROM (SELECT word_id, COUNT(*) AS num FROM sentence_word GROUP BY word_id) AS totals
 WHERE num > 1000;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top