web-dev-qa-db-fra.com

COUNT (*) dans SQL Server est-il une opération à temps constant? Sinon, pourquoi pas?

Je lisais cette discussion dans n autre post où cette question a été posée par quelqu'un d'autre. Avant de lire la discussion, j'ai toujours pensé que SQL Server (et les autres SGBD) conservent un nombre global de lignes pour chaque table quelque part dans les métadonnées, mais la discussion semble dire que ce n'est pas le cas. Pourquoi? Count(*) (sans aucun filtrage) étant une opération aussi courante, cela augmenterait considérablement s'il s'agit de O (1). Même sans tenir compte de COUNT(*), le nombre total de lignes dans une table est une information fondamentale. Pourquoi n'en prennent-ils pas note?

De plus, pourquoi devons-nous "charger" des lignes entières (comme indiqué dans le message que j'ai lié) juste pour les compter? Les index, les PK, etc. ne devraient-ils pas être suffisants pour les compter?

36
dotNET

Non, COUNT(*) n'est pas une opération à temps constant. Une COUNT(*) doit renvoyer un nombre de lignes conformes au prédicat d'analyse en cours (c'est-à-dire la clause WHERE), de sorte que seule rendrait le retour d'une propriété de métadonnées invalide. Mais même si vous n'avez pas de prédicats, le COUNT doit toujours satisfaire la sémantique d'isolement des transactions actuelle, c'est-à-dire. renvoyer le nombre de lignes visibles (par exemple validées). Ainsi, COUNT doit, et va, dans SQL Server, réellement analyser et compter les lignes. Certains systèmes permettent le retour de comptage "d'estimation" plus rapide .

En outre, en tant que commentaire secondaire, s'appuyer sur rows dans sys.partitions n'est pas fiable. Après tout, si ce décompte était garanti avec précision, nous n'aurions pas besoin de DBCC UPDATEUSAGE(...) WITH COUNT_ROWS . Il existe plusieurs scénarios qui, historiquement, entraîneraient une dérive de ce compteur en dehors de la réalité (la plupart du temps, des restaurations d'insertion minimalement enregistrées), tout ce que je sais sont fixes, mais cela laisse toujours les problèmes de 1) tables mises à niveau à partir des versions précédentes qui avaient les bogues et 2 ) autres bogues, non encore découverts.

De plus, pourquoi devons-nous "charger" des lignes entières (comme indiqué dans le message que j'ai lié) juste pour les compter? Les index ou PK, etc. ne devraient-ils pas être suffisants pour les compter?

Ce n'est pas vrai à 100%. Il existe au moins 2 scénarios qui ne chargent pas de lignes entières:

  • les index rowstore étroits ne chargent que la ligne "index", qui peut être beaucoup plus petite
  • les données du magasin de colonnes chargent uniquement les segments de colonne pertinents

Et la plupart de ce que je dis ci-dessus ne s'appliquent pas aux tables Hekaton.

56
Remus Rusanu

pourquoi devons-nous "charger" des lignes entières

Nous non. SQL Server aura tendance à utiliser le plus petit index qu'il puisse utiliser pour satisfaire la requête.

Count(*) (sans aucun filtrage) étant une telle opération courante

Je pense que vous surestimez sa prévalence. Je ne me souviens pas de la dernière fois où je me suis soucié du nombre total de lignes dans une seule table par rapport à une vue plus filtrée ou à un nombre sur une opération jointe plus complexe.

Ce serait une optimisation exceptionnellement étroite qui ne pourrait bénéficier qu'à un seul style de requête, et comme je l'ai dit, je pense que vous avez surestimé la fréquence à laquelle cela se produit.

21