2010-07-23 25 views
1

J'ai une table qui stocke des informations de photo avec id comme clé primaire:question requête tsql et l'index

id (PK), titre, album_id, posted_by, publié, nom de fichier, les balises, les cotes, date_posted

ce tableau tiendra infor de plus de 100 millions de photos et j'ai besoin pour exécuter cette requête comme celles-ci fréquemment:

1) obtenir toutes les photos (juste id, nom de fichier, les colonnes de titre) d'un album donné

id select, nom, titre à partir de photos où album_id = @AlbumId et publié = 1

2) obtenir toutes les photos publiées d'un utilisateur donné mais excluent les photos actuellement regarder album

select id, nom, titre à partir de photos où posted_by = 'bob' et album_id <> 10 et publié = 1

Je veux éviter l'index et l'analyse de la table. Je dois utiliser chercher (disons 100%) autant que possible.

Est-ce que cela peut être fait? Quel type d'index et sur quelles colonnes m'y aiderais?

Merci

+0

Quelle est la cardinalité de la colonne Publié? (C'est-à-dire, quelles sont les différentes valeurs et combien de chacune d'entre elles pourrait contenir?) –

+0

Idem pour AlbumId et posted_by: pour chaque colonne, combien de valeurs différentes sont probables, et combien de lignes pour une valeur donnée? –

+0

publié est une colonne de type bit: donc soit 1 ou 0 AlbumId: deviendra assez grand disons 10 Millions de 1 à 10M posted_by est varchar (20) donc je peux avoir de très gros utilisateurs – kheya

Répondre

2

En réalité, vous ne pourrez le découvrir vous-même en mesure de la performance avant tweak, puis tweak, et mesurer encore et encore.

Mais en fonction de votre requête, vous devriez considérer (ou au moins essayer en premier) un index non cluster comme ceci:

CREATE NONCLUSTERED INDEX IX01_Photos 
    ON dbo.Photos(album_id, published, posted_by) 
    INCLUDE(id, filename, title) 

Raisonnement:

  • fois vos requêtes les plus fréquentes ont WHERE clauses utilisant album_id et published - donc utilisez ces deux colonnes d'abord dans votre index
  • votre deuxième requête comprend également posted_by dans la clause WHERE - mettre que dans ce même i ndex comme la troisième colonne
  • afin d'éviter les recherches de signets coûteux dans la table de données réelles, vous pouvez inclure les id, filename, title colonnes de l'index

Avec toutes ces choses en place, vous devriez être voir la plupart du temps index recherche sur ce nouvel index non cluster pour satisfaire vos requêtes. Mais encore une fois: beaucoup d'autres facteurs entrent en jeu que vous n'avez probablement pas mentionnés dans votre question et peut-être même pas pensé à vous-même - mais cette approche devrait vous donner un bon point de départ pas moins.

+0

Marc, j'ai aimé votre approche et votre raisonnement !! Encore quelques questions: Le titre est la seule colonne qui peut être modifiée par l'utilisateur. Quelle incidence cela aura-t-il sur l'indice non groupé que vous proposez? J'ai une autre colonne qui stocke le nombre de vues (combien de fois) la photo a été vue. Cette colonne a augmenté de 1 chaque fois que quelqu'un voit la photo. Pensez-vous que je vais mieux Ne pas inclure ce colm dans l'index? – kheya

+0

Que l'utilisateur puisse ou non modifier le "Titre" n'a pas d'importance. Évidemment, si la colonne Titre est modifiée, l'index doit être mis à jour.Le nombre de vues: si vous avez besoin de l'utiliser dans vos requêtes, pour l'afficher - alors oui, mettez alors dans la liste des colonnes INCLUDE(). Si vous ne le faites pas, si vous recherchez un ensemble de photos et que vous souhaitez également afficher le nombre de vues, SQL Server doit passer de l'index (où il a trouvé vos critères correspondants) aux pages de données réelles récupérer le nombre de vues pour chaque hit. Ces "recherche de signets" ont tendance à être coûteux et lent. –

0

Vous n'avez pas mentionné s'il est nécessaire d'utiliser le paramètre date_posted ou id comme critère de filtrage dans la requête. Il est donc préférable d'utiliser un index CLUSTERED sur une colonne non chronologique (je suppose que le l'index actuel de CLUSTERED est le PK. Droit?).

Je créerais un index CLUSTERED sur l'album_id.

Si vous ne pouvez pas modifier l'index CLUSTERED ou il y a beaucoup d'autres questions qui bénéficient de l'index ordonné en clusters existant, je soutiens la réponse de @marc_s (et voter en conséquence.)

+0

date_posted et id col ne seront pas utilisés pour filtrer. J'ai déjà un index cluster sur la colonne id – kheya

0

Je suggère une index clusterisé sur album_id et un index secondaire sur posted_by, si le premier est celui qui sera le plus touché. Inversez-les si posted_by est touché le plus. Selon le nombre de photos pour chaque album_id ou posted_by, il peut être tout à fait possible de filtrer sur published dans le code appelant (en d'autres termes, ne l'ajoutez pas comme une restriction dans la requête, plutôt que le côté client de filtrage). Sinon, vous devrez ajouter cette contrainte publiée dans la requête, mais la restriction principale de album_id devrait signifier que seul un petit balayage sur published est encouru. Mais comme indiqué, il peut être plus facile de filtrer sur published côté client.

0

Clé primaire sur Id. Faites-le non-cluster. Je suppose que cela ne sera pas beaucoup utilisé (en particulier si toutes les recherches sont par album ou poster).

Index clusterisé sur AlbumId. On dirait qu'il serait utilisé dans la plupart des requêtes.

Index non clusterisé sur Posted_By. Avec AlbumId l'index clusterisé, il apparaîtra au niveau feuille de cet index, et agira donc comme une colonne INCLUDEd. Selon l'utilisation, il pourrait être préférable d'avoir ceci comme index clusterisé ... mais en tant que varchar (20), il prendrait plus d'espace disque, et les performances seraient pire que AlbumId (en supposant que AlbumId est un int).

Vous ne pouvez pas avoir publié en tant que colonne dans l'index, car vous ne pouvez pas indexer sur les colonnes de bits. Vous ne voudrez pas non plus - avec seulement deux valeurs possibles sur 100M + lignes, SQL ne l'utilisera probablement jamais pour optimiser les requêtes.

Je recommanderais de normaliser Posted_By (le déplacer vers sa propre table, lui donner sa propre clé de substitution, et l'utiliser comme clé étrangère dans cette table). Cela réduirait considérablement l'espace de stockage de votre table principale, augmenterait les performances globales et vous permettrait de retourner l'index clusterisé à cette colonne si nécessaire. (De plus, si "Bob" affiche sur la table, puis "Bob" de l'autre côté de la ville, comment le dites-vous à Bob?)

+0

bob a été utilisé comme un espace réservé. L'application ne permettra pas les noms d'utilisateur en double. – kheya

+0

Si la mention "En_By" est une colonne unique, définissez-la comme un index non clusterisé unique. –