Puis-je optimiser un X distinct de SELECT hugeTable query en créant un index sur la colonne x?

j'ai une table immense, d'avoir un nombre beaucoup plus restreint (ordres de grandeur) de valeurs distinctes sur certaines colonne x.

j'ai besoin de faire une requête de la forme SELECT DISTINCT x FROM hugeTable, et je veux le faire de façon relativement rapide.

j'ai fait quelque chose comme CREATE INDEX hugeTable_by_x ON hugeTable(x), mais pour une raison quelconque, même si la production est petite, l'exécution de la requête n'est pas aussi rapide. Le plan de requête montre que 97% du temps est consacré à l'Analyse d'Index hugeTable_by_x, avec un nombre estimé de lignes égal à la taille de la toute la table. Cette opération est suivie, entre autres, d'une opération de hachage.

Depuis que j'ai créé un index sur la colonne x, puis-je ne pas m'attendre à ce que cette requête s'exécute très rapidement?

notez que J'utilise Microsoft SQL Server 2005.

19
demandé sur polygenelubricants 2011-05-12 09:54:16

7 réponses

il ne s'agit probablement pas d'un problème d'indexation, mais d'un problème de conception de données. La normalisation, pour être précis. Le fait que vous devez interroger des valeurs distinctes d'un champ, et même prêt à ajouter un index, est un indicateur fort que le champ devrait être normalisé dans une table séparée avec une (petite) touche de jointure. Alors les valeurs distinctes seront disponibles immédiatement en balayant la table étrangère de lookup beaucoup plus petite.

mise à Jour

Comme solution de contournement, vous pouvez créer un vue indexée sur un agrégat par le champ "distinct". COUNT_BIG est un agrégat qui est autorisé dans les vues indexées:

create view vwDistinct
with schemabinding
as select x, count_big(*)
from schema.hugetable
group by x;

create clustered index cdxDistinct on vwDistinct(x);

select x from vwDistinct with (noexpand);
22
répondu Remus Rusanu 2015-10-24 08:54:03

SQL Server n'implémente aucune facilité pour rechercher directement la valeur distincte suivante dans un index en sautant les doublons en cours de route.

si vous avez beaucoup de doubles, alors vous pouvez utiliser un CTE récursif pour simuler ceci. La technique vient de ici. ("Super-rapide DISTINCTES à l'aide d'une expression de table commune récursive"). Par exemple:

with recursivecte as (
  select min(t.x) as x
  from hugetable t
  union all
  select ranked.x
  from (
    select t.x,
           row_number() over (order by t.x) as rnk
    from hugetable t
    join recursivecte r
      on r.x < t.x
  ) ranked
  where ranked.rnk = 1
)
select *
from recursivecte
option (maxrecursion 0)
6
répondu Martin Smith 2017-11-03 14:30:41

si vous connaissez les valeurs à l'avance et qu'il y a un index sur la colonne x (ou si chaque valeur est susceptible d'apparaître rapidement sur un scan seq de toute la table), il est beaucoup plus rapide d'interroger chacune individuellement:

select vals.x
from [values] as vals (x)
where exists (select 1 from bigtable where bigtable.x = vals.x);

Continuer en utilisant exists () fera autant de recherches d'index qu'il y a de valeurs valides.

la façon dont vous l'avez écrit( ce qui est correct si les valeurs ne sont pas connues à l'avance), le moteur de requête devra lire la table entière et hachez agréger le mess pour extraire les valeurs. (Ce qui est l'indice inutile.)

1
répondu Denis de Bernardy 2011-05-12 10:22:04

Non. Mais il y a quelques solutions de rechange (à l'exclusion de la normalisation):

une fois l'index en place, il est alors possible d'implémenter en SQL ce que l'optimiseur peut faire automatiquement:

https://stackoverflow.com/a/29286754/538763 (plusieurs solutions de contournement cité)

D'autres réponses disent que vous pouvez normaliser ce qui résoudrait votre problème mais même une fois que son serveur SQL normalisé aime toujours effectuer un scan pour trouver le max() dans le(s) groupe (s). Solutions de contournement:

https://dba.stackexchange.com/questions/48848/efficiently-query-max-over-multiple-ranges?rq=1

1
répondu crokusek 2017-05-23 12:02:08

peut-être. Bien qu'il n'est pas garanti, il dépend entièrement de la requête.

je suggère la lecture de cet article par Gail Shaw (partie 1 et partie 2).

0
répondu Oded 2011-05-12 05:58:05

en faisant un SELECT DISTINCT sur un champ indexé, un scan d'index a du sens, car l'exécution doit encore balayer chaque valeur de l'index pour la table entière (en supposant qu'il n'y ait pas de WHERE l'article, comme cela semble être le cas, par votre exemple).

les indices ont habituellement plus d'impact sur WHERE conditions,JOINS et ORDER BY les clauses.

0
répondu Jerad Rose 2011-05-12 06:04:38

selon votre description du plan d'exécution, je pense que c'est la meilleure exécution possible.

le balayage de L'Index lit l'index entier tel qu'il est stocké (pas dans l'ordre de l'index), la correspondance de hachage fait le distinct.

il pourrait y avoir d'autres moyens pour contourner votre problème. Dans SQL Server, les vues indexées me viennent à l'esprit. Cependant, cela pourrait vous donner un grand succès pour écrire sur cette table.

0
répondu Markus Winand 2011-05-12 06:04:43