2009-06-10 8 views
1

J'ai récemment remarqué que nous avons un certain nombre de tables stockées en tas (pas d'index clusterisé). Souhaitez-vous créer des index clusterisés sur eux sélectivement, à travers le conseil, ou pas du tout? Toute autre sagesse ou conseil?Tables SQl Server: pour entasser ou non?

Il existe des tables de "codes" avec 25 lignes ou plus. Cependant, il y en a plusieurs avec plus d'un million de lignes.

EDIT des «grandes tables», toutes ont déjà des index, mais pas des en cluster. quelques-uns sont des tables de log, où ils insèrent juste, avec peu de lecture. Il y en a quelques-uns qui sont assez importants et qui sont pour la plupart simplement insérés et lus ensuite par l'application.

EDIT il y a PK sur toutes les tables, avec le peu que je suis intéressé, ils sont principalement vient d'être inséré une fois, mais lu plusieurs fois pour afficher les écrans.

Sur certaines de ces tables, ils sont insérés dans un bloc ou des lignes associées à la fois et lus plusieurs fois sans mise à jour ou le groupe est complètement supprimé puis réinséré en tant que bloc. Ils sont généralement lus dans le bloc pour afficher ou faire des calculs.

Sur un autre "type" de ces tables, les lignes sont insérées plusieurs fois dans des groupes de lignes apparentées, avec des groupes différents insérés tout le temps. à l'écran, le groupe complet devra être retourné. par exemple, au fil du temps ces groupes de lignes sont insérées (où un groupe pourrait être rangées 5-50):

1:00pm A1, B1, C1, 
1:30pm A2, B2, C2, 
2:00pm A3, B3, C3, D1 
2:30pm A4,  C4, D2 
3:00pm   C5, D3, E1 
3:30pm    D4, E2 

écran aurait besoin pour afficher ensemble complet de A: A1 + A2 + A3 + A4

EDIT sur la base de réponse @gbn mentionner au sujet de la fragmentation, j'ai utilisé cette query from marc_s et a trouvé les informations de fragmentation suivantes pour les tables de tas avec des millions + lignes et qui sont lus plusieurs fois et utilisé par les écrans:

TableName index_type alloc_unit_type index_depth index_level avg_fragmentation_in_percent fragment_count avg_fragment_size_in_pages page_count avg_page_space_used_in_percent record_count ghost_record_count Version_ghost_record_count min_record_size_in_bytes max_record_size_in_bytes avg_record_size_in_bytes forwarded_record_count 
--------- ---------- --------------- ----------- ----------- ---------------------------- -------------- -------------------------- ---------- ------------------------------ ------------ ------------------ -------------------------- ------------------------ ------------------------ ------------------------ ---------------------- 
TABLE_A HEAP  IN_ROW_DATA  1   0   95.8294717330862    2069   8.18511358144031   16935  98.2659995058068    1125786  3     0       80      164      117.671     0 
TABLE_A HEAP  IN_ROW_DATA  1   0   95.8294717330862    2069   8.18511358144031   16935  98.2659995058068    1125786  3     0       80      164      117.671     0 
TABLE_A HEAP  IN_ROW_DATA  1   0   95.8314034275127    2070   8.18212560386473   16937  98.2559303187546    1125793  11     0       80      164      117.672     0 
TABLE_B HEAP  IN_ROW_DATA  1   0   99.2541594951233    1734   6.44982698961938   11184  94.5866567828021    1222729  0     0       68      82      68.037     0 
TABLE_B HEAP  IN_ROW_DATA  1   0   99.2541594951233    1734   6.44982698961938   11184  94.5866567828021    1222729  0     0       68      82      68.037     0 
TABLE_B HEAP  IN_ROW_DATA  1   0   99.197247706422    1735   6.44726224783862   11186  94.5725228564369    1222745  23     0       68      82      68.038     0 
TABLE_C HEAP  IN_ROW_DATA  1   0   71.5785224061365    1777   10.9527293190771   19463  97.4122807017544    2237831  0     0       9      84      66.588     2485 
TABLE_C HEAP  IN_ROW_DATA  1   0   71.5785224061365    1777   10.9527293190771   19463  97.4122807017544    2237831  0     0       9      84      66.588     2485 
TABLE_C HEAP  IN_ROW_DATA  1   0   71.589991928975    1778   10.9476940382452   19465  97.4023844823326    2237832  0     0       9      84      66.588     2485 
TABLE_D HEAP  IN_ROW_DATA  1   0   40.0769404842725    1773   19.7535250987028   35023  98.0193106004448    2778169  0     0       98      112      98.041     0 
TABLE_D HEAP  IN_ROW_DATA  1   0   40.0904977375566    1774   19.7480270574972   35033  98.0175315048184    2778821  0     0       98      112      98.044     0 
TABLE_D HEAP  IN_ROW_DATA  1   0   40.1040488577245    1775   19.7385915492958   35036  98.0142451198419    2778948  0     0       98      112      98.045     0 
TABLE_E HEAP  IN_ROW_DATA  1   0   97.1619365609349    2911   8.11473720371007   23622  99.390066716086    3333693  0     0       55      69      55.017     0 
TABLE_E HEAP  IN_ROW_DATA  1   0   97.1628838451268    2912   8.11332417582418   23626  99.3852359772671    3334016  0     0       55      69      55.018     0 
TABLE_E HEAP  IN_ROW_DATA  1   0   97.1638304971638    2913   8.11122554067971   23628  99.3799357548802    3334100  0     0       55      69      55.018     0 
TABLE_F HEAP  IN_ROW_DATA  1   0   21.9911471599199    8903   36.3093339323823   323262  94.6116753150482    4734053  44     0       521      535      521.046     0 
TABLE_F HEAP  IN_ROW_DATA  1   0   21.9911471599199    8903   36.3093339323823   323262  94.6116876698789    4734053  50     0       521      535      521.046     0 
TABLE_F HEAP  IN_ROW_DATA  1   0   21.9930761622156    8904   36.3057053009883   323266  94.6112428959723    4734079  78     0       521      535      521.047     0 
TABLE_G HEAP  IN_ROW_DATA  1   0   66.1932151660993    5649   11.9943352805806   67756  96.7873733629849    6632610  0     0       78      92      78.047     0 
TABLE_G HEAP  IN_ROW_DATA  1   0   66.1932151660993    5649   11.9943352805806   67756  96.7873733629849    6632610  0     0       78      92      78.047     0 
TABLE_G HEAP  IN_ROW_DATA  1   0   66.1971830985916    5650   11.9925663716814   67758  96.7855572028663    6632648  11     0       78      92      78.048     0 
TABLE_H HEAP  IN_ROW_DATA  1   0   11.5377268385864    5585   67.4340196956132   376619  92.3860637509266    6897347  0     0       9      427      406.418     3 
TABLE_H HEAP  IN_ROW_DATA  1   0   11.5449915110357    5576   67.5530846484935   376676  92.3849023968372    6898289  0     0       9      427      406.419     3 
TABLE_H HEAP  IN_ROW_DATA  1   0   11.5487458087518    5578   67.5313732520617   376690  92.3848035581913    6898534  0     0       9      427      406.42     3 
TABLE_I HEAP  IN_ROW_DATA  1   0   96.7330677290837    9715   8.232.3321225599209    3152049  0     0       76      534      195.879     0 
TABLE_I HEAP  IN_ROW_DATA  1   0   96.7333930883378    9716   8.23157678056814   79978  96.3298122065728    3152142  0     0       76      534      195.879     0 
TABLE_I HEAP  IN_ROW_DATA  1   0   96.7337183827923    9717   8.23114129875476   79982  96.3323696565357    3152420  0     0       76      534      195.876     0 
TABLE_J HEAP  LOB_DATA  1   0   0       NULL   NULL      87553  95.5205090190264    7790594  0     0       84      98      84.91     NULL 
TABLE_J HEAP  IN_ROW_DATA  1   0   31.2985438510012    23539   25.4966651089681   600166  96.4532863849765    7807684  0     0       435      1213      598.261     0 
TABLE_J HEAP  IN_ROW_DATA  1   0   31.2994591137993    23540   25.4959218351742   600174  96.4530145787003    7807780  0     0       435      1213      598.26     0 
TABLE_J HEAP  IN_ROW_DATA  1   0   31.3022047558782    23543   25.4936074417024   600196  96.4526068692859    7808096  0     0       435      1213      598.255     0 

Je ne sais pas pourquoi il existe plusieurs lignes pour chaque table, mais les valeurs avg_fragmentation_in_percent semblent assez élevées pour la quasi-totalité de ces tables. Cette fragmentation serait-elle un problème de performance lors de la lecture? Un index clusterisé serait-il conseillé de les défragmenter?

+0

Ont-ils des PK ou seulement des index? Si les lignes ne sont pas mises à jour après l'écriture (donc pas d'enregistrements transférés à partir d'une taille de ligne accrue) et que vous n'avez pas besoin d'accès en lecture à distance, il n'y a peut-être pas de raison impérieuse. Bien qu'il semble que l'équilibre efficace des données anciennes peut être beaucoup plus difficile. – ahains

+1

Si vous avez des index non clusterisés sur vos tables, et que vous les utilisez principalement pour la lecture, je recommanderais * FORTEMENT * un index clusterisé sur un champ toujours croissant, unique, stable et étroit (comme une ID INTENTION) pour accélérer les choses en haut –

+0

Les tables de journaux, comme vous l'avez mentionné, qui ne contiennent pratiquement rien d'autre que des insertions, pourraient même sans aucun indice - après tout, même les meilleurs indices ralentiront vos insertions. –

Répondre

3

Ajoutez toujours un index cluster. Sans index clusterisé, vous ne pouvez pas compacter ou défragmenter rapidement la table. Sans cela, vous ne pouvez pas.

Simpliste, mais je parie que certains des problèmes de performance pourraient être attribués à des données mal organisées.

0

Je considérerais mettre un index groupé sur les grandes tables. L'index clusterisé définit l'ordre physique de stockage des enregistrements. La conséquence en est que les lignes de la table peuvent être stockées plus efficacement et réduire la fragmentation. Je suis sûr qu'il y aura au moins une colonne dans la table qui pourrait être un candidat pour mettre un index en cluster. (Et sinon, vous pouvez créer une nouvelle colonne, qui contient la date et l'heure auxquelles l'enregistrement a été créé, et vous mettre un index clusterisé sur cette colonne, je pense que c'est encore mieux que pas de CI du tout). Edit: si les tables volumineuses sont en effet des tables de journalisation qui ne sont pas lues fréquemment, elles peuvent être laissées en tas.

0

Cela dépend de la façon dont les tables sont utilisées. Normalement, je veux un index clusterisé sur une table avec des millions d'enregistrements, mais vous devez également considérer comment la table est utilisée. L'ajout d'un index ralentira les insertions car il doit rechercher la page appropriée pour chaque nouvel enregistrement (et éventuellement insérer une nouvelle page) plutôt que de simplement l'ajouter.Si ces titres sont principalement des "dumps" pour les données et sont rarement vérifiés (comme la journalisation d'urgence, par exemple), alors les laisser seuls pourrait être meilleur.

Comme toujours, vous devriez profil pour savoir ce qui fonctionne le mieux pour votre application ou votre système.

5

On dirait que la base de données a été créée par quelqu'un qui savait ce qu'il faisait. Les tables de journalisation et les tables de petits codes sont exactement là où les tas ont du sens.

S'il n'y a aucun problème avec la base de données, je le laisserais tel quel!

+0

réponse facile si elles étaient toutes les tables de log et de codes, mais ils ne sont pas. En outre, je recherche un point lent dans l'application, et je vais réparer l'une des grandes tables de tas. Je me demande simplement si je devrais changer quelques autres tables de la même manière. –

+0

Vous avez demandé "Voulez-vous créer des index clusterisés sur eux sélectivement, à travers le conseil, ou pas du tout". Je dirais "pas du tout", à moins qu'il y ait un "point lent" qui est démontré résolu en ajoutant l'index clusterisé :) – Andomar

+1

Je suis avec Andomar - on dirait que le designer savait ce qu'il faisait, et ainsi je ' d dire "non". Qu'un point lent développé plus tard après la taille des données a augmenté n'est pas discréditer le concepteur, et l'ajout d'un index pour répondre à ce ralentissement particulier est parfaitement bien - juste ne pas exagérer. Les index inutilisés peuvent avoir l'effet contraire de leur intention et de votre performance. Vous devriez PROFILER pour savoir où, exactement, vos problèmes sont et ce qui fonctionnera le mieux pour les corriger. –

2

pour une grande table Un index clusterisé est toujours une bonne idée. même pour insérer seulement la table. bien sûr, votre clé de cluster devrait être une valeur toujours croissante.

-1

Un problème avec un index clusterisé sur de grandes tables est que la mémoire tampon (RAM) requise pour stocker l'index est égale à la taille de la table. Il n'y a pas d'index séparé. Un index non clusterisé stocke uniquement les données de l'index, puis la clé primaire de la table ou un refid. Un index normal peut donc plus facilement s'intégrer dans la RAM. Si vous effectuez des recherches à l'aide de l'index clusterisé et que la table est volumineuse, vous pouvez facilement ralentir les choses. Si votre index clusterisé fait partie de la date et que vos recherches portent toutes sur des dates récentes, il se peut que l'index clusterisé ne nuise pas aux performances de recherche puisque vous n'accédez jamais à tous les index.

Je ne suis pas d'accord avec les affiches affirmant que l'index clusterisé réduira la fragmentation des données. Cela augmente la fragmentation des données. Sur une table normale, seule la suppression entraîne une fragmentation. Lorsque vous ajoutez des lignes à une table en cluster ou modifiez le champ a de l'index cluster, SQL doit réorganiser la table. Cela signifie casser et ajouter des pages de données qui augmentent la fragmentation. C'est pourquoi tout le monde recommande de prendre soin de choisir un champ pour le clustering qui a) ne change pas souvent si jamais, et b) augmente toujours.

Je trouve qu'un index clusterisé est utile sur les grandes tables lorsque vos requêtes doivent renvoyer plusieurs lignes "liées" souvent. Vous pouvez utiliser le cluster afin que les lignes associées soient stockées consécutivement et plus facilement récupérées par SQL. Je ne classerais pas nécessairement une grande table de sorte que j'aurais un nouvel index pour la recherche.

Le seul avantage que le clustering a, comme un index de couverture, est que l'index contient les données que la requête tente de renvoyer. Il n'y a pas d'étape supplémentaire entre l'index et la table pour obtenir les données. En fin de compte, vous devez sortir le profileur et effectuer quelques tests.

Est-ce que je comprends bien ou manque quelque chose?

+0

Il ya beaucoup de choses confuses ici. 1) La chose index non clusterisée est un hareng rouge. Vous pouvez créer le même NCI sur une table avec un index clusterisé si cela facilite l'utilisation du tampon d'E/S. 2) Un index clusterisé sur une clé appropriée (croissant de façon monotone) sera moins fragmenté qu'un tas. 3) Les suppressions affectent la fragmentation de n'importe quoi, mais si vous supprimez une plage par rapport à la clé de cluster, ce n'est pas le cas. Si vous effectuez un test, vous constaterez probablement qu'un tas est surperformé dans presque toutes les métriques, même en ajoutant simplement un index clusterisé INT IDENTITY simple. –

+0

Le seul véritable inconvénient d'un index clusterisé est de supporter des charges de travail simultanées très élevées. plus de verrouillage sur cette page, mais cela peut être traité (diviser le tableau en plusieurs partitions, et la partition sur la clé modulo le nombre de partitions: http://blogs.msdn.com/b/blogdoezequiel/archive/2013/05 /23/pagelatch-ex-waits-and-heavy-inserts.aspx) –

Questions connexes