Qu'est-ce qui peut accélérer une requête de comptage SQL?

9

Lorsque vous effectuez une requête SQL de comptage (agrégé), qu'est-ce qui peut accélérer le temps d'exécution dans ces 3 systèmes de base de données? Je suis sûr que beaucoup de choses pourraient l'accélérer (matériel pour un), mais je ne suis qu'un DBA novice, donc je suis sûr que j'obtiendrai quelques réponses ici. J'ai migré environ 157 millions de lignes vers une base de données SQL Server, et cette requête prend une éternité. Mais dans ma base de données Netezza source, cela prend quelques secondes.

Par exemple:

Netezza 6:

SELECT COUNT(*) FROM DATABASENAME..MYTABLE

Oracle 11g:

SELECT COUNT(*) FROM MYTABLE

SQL Server 2012:

SELECT COUNT(*) FROM DATABASENAME.[dbo].[MYTABLE]
MacGyver
la source
1
Avez-vous besoin de le faire une seule fois ou à plusieurs reprises?
Jon Seigel
@ JonSeigel, nous effectuons des chargements incrémentiels et nous comparons chaque jour les enregistrements entre les systèmes de base de données pour nous assurer que les nombres s'additionnent. Donc, à plusieurs reprises.
MacGyver

Réponses:

10

Netezza est une appliance conçue pour exceller dans les analyses de grandes tables, c'est pourquoi vous obtenez des résultats aussi rapides sur ce système.

Pour votre serveur SQL, vous pouvez considérablement accélérer le nombre de lignes en effectuant une requête à partir du DMV sys.dm_db_partition_stats.

SELECT s.name AS [Schema], o.name AS [Table], SUM(p.row_count) AS [RowCount]
FROM sys.dm_db_partition_stats p JOIN sys.objects o
ON p.object_id = o.object_id JOIN sys.schemas s
ON o.schema_id = s.schema_id
WHERE p.index_id < 2
AND o.object_id = object_id('MyTable')
GROUP BY o.name, s.name;

Dans un environnement de transaction élevée, ce DMV n'est pas garanti d'être précis à 100%. Mais d'après votre question, il semble que vous effectuez simplement le comptage des lignes pour vérifier chaque table après votre migration, donc cette requête devrait fonctionner pour vous.

Patrick Keisler
la source
4
@Phil pourquoi? Si vous parcourez les tableaux et effectuez un SELECT COUNT (*) coûteux à partir de chacun - quelle est la précision du premier résultat une fois que vous avez atteint le dernier tableau?
Aaron Bertrand
1
Pour plus de clarté, Phil avait déclaré: "Utiliser le dictionnaire de données, qui ne fournit pas de résultats précis à 100%, est un mauvais conseil. À mon avis, la réponse devrait être modifiée pour supprimer la suggestion ou supprimée - rappelez-vous que les gens recherchent ces réponses sur google et aveuglément couper et coller ... "Je reconnais que la clause de non-responsabilité est importante (et il y aurait des cas marginaux où les métadonnées ne renvoient pas de résultats raisonnables), je ne suis pas d'accord pour dire que l'utilisation des vues de métadonnées en général est un mauvais conseil.
Aaron Bertrand
5

Voici une solution SQL Server qui utilise l' COUNT_BIGintérieur d'une vue indexée. Cela vous permettra d'obtenir un compte cohérent avec les transactions sans la surcharge des analyses de grande table ou d'index, et sans avoir besoin du stockage requis pour ce dernier:

CREATE TABLE [dbo].[MyTable](id int);
GO

CREATE VIEW [dbo].[MyTableRowCount]
    WITH SCHEMABINDING
AS

    SELECT
        COUNT_BIG(*) AS TableRowCount
        FROM [dbo].[MyTable];
GO

CREATE UNIQUE CLUSTERED INDEX IX_MyTableRowCount
    ON [dbo].[MyTableRowCount](TableRowCount);
GO

SELECT
    TableRowCount
    FROM [dbo].[MyTableRowCount] WITH(NOEXPAND);

Cela nécessitera une seule analyse initiale (sans s'éloigner de cela) et ajoutera un peu de surcharge aux manipulations incrémentielles des données de table. Si vous effectuez de grandes opérations avec beaucoup de données (par opposition à de nombreuses petites opérations), je pense que les frais généraux sur les changements devraient être négligeables.

Jon Seigel
la source
@SQLKiwi: Comment se fait-il que les lectures soient bloquées avant 2012? Bogue SQL Server?
Jon Seigel
@JonSeigel - My 0,05 $: les index en cluster normaux sur une table normale créés hors ligne appliquent un verrou Sch-M sur la table. Sur une vue, bien sûr, ce n'est pas nécessaire, mais cela signifie une modification de l'opération Créer un index pour créer un cas spécial pour la vue indexée - ce qui a été fait pour SQL2012. À mon humble avis, bien sûr.
Fabricio Araujo du
3

Dans Oracle, un index d'arbre binaire sur une colonne NOT NULL peut être utilisé pour répondre à COUNT (*). Il sera plus rapide dans la plupart des cas qu'un FULL TABLE SCAN car les index sont généralement plus petits que leur table de base.

Cependant, un index d'arbre binaire régulier sera toujours énorme avec 157 Mrows. Si votre table n'est pas mise à jour simultanément (c'est-à-dire uniquement le processus de chargement par lots), vous souhaiterez peut-être utiliser un index bitmap à la place.

Le plus petit index bitmap serait quelque chose comme ceci:

CREATE BITMAP INDEX ix ON your_table(NULL);

Les entrées nulles sont prises en compte par un index bitmap. L'index résultant sera minuscule (20-30 blocs de 8k par million de lignes) par rapport à un index d'arbre binaire normal ou à la table de base.

Le plan résultant doit montrer les opérations suivantes:

----------------------------------------------
| Id  | Operation                     | Name | 
----------------------------------------------
|   0 | SELECT STATEMENT              |      |
|   1 |  SORT AGGREGATE               |      |
|   2 |   BITMAP CONVERSION COUNT     |      |
|   3 |    BITMAP INDEX FAST FULL SCAN| IX   |
----------------------------------------------

Si votre table est mise à jour simultanément, un index bitmap avec une valeur unique sera un point de discorde et ne devrait pas être utilisé.

Vincent Malgrat
la source
3

Dans Oracle, une requête de comptage simple est souvent exécutée en analysant un index au lieu d'une table entière. L'index doit être un index bitmap ou défini sur une colonne avec la contrainte NOT NULL. Pour les requêtes plus complexes qui nécessitent une analyse complète de la table, vous pouvez utiliser une requête parallèle.

Pour activer la requête parallèle (Enterprise Edition requise), vous pouvez utiliser l'indice d'optimisation:

select /*+ PARALLEL(mytable, 12) */ count(*) from mytable;

Ou activez la requête parallèle pour toutes les requêtes sur la table:

alter table mytable parallel 12;
sjk
la source