web-dev-qa-db-fra.com

Performances de comptage SQL (*)

J'ai une table SQL BookChapters avec plus de 20 millions de lignes. Il a une clé primaire en cluster (bookChapterID) et n'a pas d'autres clés ou index. Il faut des millisecondes pour exécuter la requête suivante

if (select count(*) from BookChapters) = 0
...

Cependant, cela prend plus de 10 minutes quand je le change comme ça

if (select count(*) from BookChapters) = 1
...

ou

if (select count(*) from BookChapters) > 1
...

Pourquoi donc? Comment puis-je obtenir select count(*) pour s'exécuter plus rapidement?

35
danmiao

Mikael Eriksson a une bonne explication ci-dessous pourquoi la première requête est rapide:

Le serveur SQL l'optimise en: if exists(select * from BookChapters). Il va donc chercher la présence d'une ligne au lieu de compter toutes les lignes du tableau.

Pour les deux autres requêtes, SQL Server utiliserait la règle suivante. Pour effectuer une requête comme SELECT COUNT(*), SQL Server utilisera l'index non-clustered le plus étroit pour compter les lignes. Si la table n'a pas d'index non clusterisé, elle devra analyser la table.

De plus, si votre table a un index clustered, vous pouvez obtenir votre compte encore plus rapidement en utilisant la requête suivante (empruntée à ce site Obtenez rapidement le nombre de lignes! )

--SQL Server 2005/2008
SELECT OBJECT_NAME(i.id) [Table_Name], i.rowcnt [Row_Count]
FROM sys.sysindexes i WITH (NOLOCK)
WHERE i.indid in (0,1)
ORDER BY i.rowcnt desc

--SQL Server 2000
SELECT OBJECT_NAME(i.id) [Table_Name], i.rows [Row_Count]
FROM sysindexes i (NOLOCK)
WHERE i.indid in (0,1)
ORDER BY i.rows desc

Il utilise la table système sysindexes. Plus d'informations que vous pouvez trouver ici SQL Server 20 , SQL Server 2005 , SQL Server 2008 , SQL Server 2012

Voici un autre lien Pourquoi mon SELECT COUNT (*) fonctionne-t-il si lentement? avec une autre solution. Il montre la technique utilisée par Microsoft pour afficher rapidement le nombre de lignes lorsque vous cliquez avec le bouton droit sur le tableau et sélectionnez les propriétés.

select sum (spart.rows)
from sys.partitions spart
where spart.object_id = object_id(’YourTable’)
and spart.index_id < 2

Vous devriez constater que cela revient très rapidement quel que soit le nombre de tables dont vous disposez.

Si vous utilisez toujours SQL 2000, vous pouvez utiliser la table sysindexes pour obtenir le nombre.

select max(ROWS)
from sysindexes
where id = object_id(’YourTable’)

Ce nombre peut être légèrement différent selon la fréquence à laquelle SQL met à jour la table sysindexes, mais il est généralement correct (ou au moins assez proche).

53
Aleksey Cherenkov

essayez ceci si vous voulez seulement connaître le nombre de lignes:

exec sp_spaceused [TABLE_NAME]
12
ehsandotnet

Si vous regardez les plans d'exécution de vos requêtes, vous verrez ce qui se passe.

Votre première requête if (select count(*) from BookChapters) = 0 est reconnue par l'optimiseur de requête comme la même chose que if exists(select * from BookChapters). SQL Server sait que l'expression est vraie si au moins une ligne est présente, il recherche donc la présence d'une ligne au lieu de compter toutes les lignes de la table.

Pour vos autres requêtes, cela ne peut pas être aussi intelligent et vous devez compter le nombre de lignes dans le tableau avant de pouvoir décider si l'expression est vraie ou fausse.

7
Mikael Eriksson

Avez-vous envisagé la requête select count(BookChapterId) from BookChapterTable? - où `BookChapterId est un index non cluster. Cela devrait le faire fonctionner beaucoup plus rapidement.

Selon la façon dont la table est utilisée et les lignes accédées, l'interrogation sur un index non cluster peut être le point clé: je viens de prendre quelques points de MDSN:

  • Avant de créer des index non clusterisés, comprenez comment vos données seront accessibles. Envisagez d'utiliser des index non cluster pour:
  • Colonnes contenant un grand nombre de valeurs distinctes, telles qu'un
    combinaison de nom et prénom (si un index cluster est utilisé pour d'autres colonnes). S'il y a très peu de valeurs distinctes, telles que
    seulement 1 et 0, la plupart des requêtes n'utiliseront pas l'index car une table
    la numérisation est généralement plus efficace.
  • Requêtes qui ne renvoient pas de grands jeux de résultats.
  • Colonnes fréquemment impliquées dans les conditions de recherche d'une requête (WHERE
    ) qui renvoient des correspondances exactes.
  • Applications de système d'aide à la décision pour lesquelles des jointures et des regroupements sont fréquemment requis. Créez plusieurs index non clusterisés sur les colonnes impliquées dans les opérations de jointure et de regroupement, et un index cluster sur toutes les colonnes de clé étrangère.
  • Couvrant toutes les colonnes d'une table dans une requête donnée. Cela élimine complètement l'accès à la table ou à l'index cluster.
5
EL Yusubov

essayez ceci, si vous avez besoin de détecter, si la table a plusieurs lignes:

if (SELECT COUNT(*) FROM (SELECT TOP 2 * FROM BookChapters) AS b) > 1
2
WURMi