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?
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).
essayez ceci si vous voulez seulement connaître le nombre de lignes:
exec sp_spaceused [TABLE_NAME]
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.
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:
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