2010-03-02 5 views
1

Si j'avais une table avec les colonnes:colonnes id ou les clés primaires en cluster/cohérence de la base

  • Artiste
  • Album
  • Chanson
  • NumberOfListens

... est Il est préférable de mettre une clé primaire en cluster sur Artist, Album et Song ou d'avoir une colonne id auto-incrémentée et de mettre une contrainte unique sur Artist, Album et Song.

Quelle est l'importance de la cohérence de la base de données? Si la moitié de mes tables ont des clés primaires groupées et l'autre moitié une colonne id avec des contraintes uniques, est-ce mauvais ou cela n'a-t-il pas d'importance? Les deux façons me paraissent identiques, mais je ne connais pas la norme de l'industrie ni celle qui est la meilleure et pourquoi.

Répondre

1

Vous avez vraiment besoin de garder deux questions: à part

1) la clé primaire est une construction logique - l'une des clés candidats qui identifie de façon unique et fiable chaque ligne de votre table. Cela peut être quelque chose, vraiment - un INT, un GUID, une chaîne - choisissez ce qui est le plus logique pour votre scénario. Vous référencez les clés primaires dans vos contraintes de clé étrangère, celles-ci sont donc cruciales pour l'intégrité de votre base de données. Utilisez-les - toujours - période.

2) la regroupement clé (la colonne ou des colonnes qui définissent le « index cluster » sur la table) - c'est un physique chose liée au stockage, et ici, un petit, unique, stable, jamais -augmenter le type de données est votre meilleur choix - INT ou BIGINT comme option par défaut. Par défaut, la clé primaire sur une table SQL Server est également utilisée comme clé de clustering - mais cela ne doit pas nécessairement être le cas, vous pouvez facilement choisir une colonne qui n'est pas votre clé primaire pour être votre clustering clé.

Ensuite, il y a un autre problème à prendre en compte: la clé de clustering sur une table sera également ajoutée à chaque entrée de chaque index non cluster de votre table - vous voulez donc vous assurer qu'elle est aussi petite que possible. Généralement, un INT avec 2+ milliards de lignes devrait suffire pour la grande majorité des tables - et comparé à une VARCHAR (20) comme clé de clustering, vous pouvez économiser des centaines de mégaoctets de stockage sur disque et dans la mémoire du serveur.

Un peu plus de matière à réflexion - d'excellentes choses par Kimberly Tripp - lisez-le, relisez-le, digérez-le! C'est l'évangile d'indexation de SQL Server, vraiment.

Marc

+0

+1, bien mis !!! –

+0

Désolé je ne peux pas entrer trop dans les détails sur la base de données sur laquelle je travaille. Il a environ 50 tables et il est trop complexe pour taper plus de détails. Êtes-vous en train de dire que la mise en cluster de clés primaires ou même la mise en cluster de colonnes qui ne sont pas des clés primaires provoquent un vidage dans la mémoire du serveur? En utilisant mon exemple, pratiquement chaque table de cette base de données a une colonne Artiste et Album comme clé primaire, puis 1 à 3 autres colonnes comme clé (s) primaire. C'est mal conçu et je le réorganise. – Sarah

+0

@Sarah: si votre ** clef de cluster ** est assez grande (par exemple un VARCHAR (50) ou pire, deux colonnes ou plus), alors OUI - vous gaspillez de l'espace mémoire disque et serveur - et vous ' Je n'en retire pas vraiment grand-chose. –

5

Je ne mettrais jamais une clé primaire sur des colonnes de texte long comme: Artist, Album et Song. Utilisez un ID d'incrémentation automatique qui est le PK en cluster. Si vous souhaitez que l'artiste, l'album et la chanson soient uniques, ajoutez un index unique sur les trois. Si vous souhaitez effectuer une recherche par album ou par morceau, indépendamment de l'artiste indépendant, vous aurez besoin d'un index pour chacun d'entre eux, ce qui attirera le PK. Les économies ne sont pas seulement l'espace disque mais dans le cache mémoire, et plus de clés sur une page.

0

Les index clusterisés sont parfaits pour les requêtes basées sur les plages. Par exemple, une date de consignation ou une date de commande. En mettre un sur Artist, Album et Song provoquera [probablement] une fragmentation lorsque vous insérerez de nouvelles lignes.

Si votre base de données le prend en charge, ajoutez une clé primaire non groupée sur Artist, Album et Song et appelez-le bien. Ou ajoutez simplement une touche unique sur Artiste, Album et Chanson. Avoir une clé primaire auto-incrémentée ne serait vraiment utile que si vous deviez avoir l'intégrité référentielle d'une autre table.

+1

Un mythe urbain classique - la requête range ne concerne que la troisième caractéristique d'un index clusterisé, beaucoup plus importante étant la recherche physique des lignes de données réelles. (ainsi la clé de clustering est ajoutée à tous les index non clusterisés et doit donc être aussi petite que possible), et l'ordre physique de la table (qui - en tant qu'effet secondaire - rend certaines requêtes de distance un peu plus efficaces qu'avec un inde non-cluster X). Voir l'article du blog de Kim Tripp pour une excellente discussion de ceci: http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx –

+0

@marc_s: I ne citerait pas l'un des avantages ou des cas d'utilisation comme un mythe urbain;) Je n'ai simplement pas inclus tous les aspects des index clusterisés par rapport aux non-cluster pour la discussion. D'autres personnes ont contribué à ces aspects après avoir répondu. J'ai fourni ce que je ferais, qui est de créer une clé unique. – beach

0

Sans connaître les exigences exactes, en général vous auriez probablement une table d'artiste, et éventuellement une table d'album aussi. Une table de chansons serait alors une combinaison unique d'identifiant d'artiste, d'identifiant d'album et de chanson. J'appliquerais l'unicité par un index ou une contrainte en fonction de l'application, et j'utiliserais un identifiant pour une clé primaire.

0

Tout d'abord, il y a déjà un problème car les données ne sont pas normalisées. Création de n'importe quel sorte d'index sur un tas de colonnes de texte est quelque chose qui devrait être évité autant que possible. Même si ces colonnes ne sont pas du texte (et je suppose qu'elles le sont), cela n'a toujours pas de sens d'avoir l'artiste, l'album et la chanson dans la même table. Une meilleure beaucoup design pour ce serait:

Artists (
    ArtistID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED, 
    ArtistName varchar(100) NOT NULL) 

Albums (
    AlbumID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED, 
    ArtistID int NOT NULL, 
    AlbumName varchar(100) NOT NULL, 
    CONSTRAINT FK_Albums_Artists FOREIGN KEY (ArtistID) 
     REFERENCES Artists (ArtistID)) 

Songs (
    SongID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED, 
    AlbumID int NOT NULL, 
    SongName varchar(100) NOT NULL, 
    NumberOfListens int NOT NULL DEFAULT 0 
    CONSTRAINT FK_Songs_Albums FOREIGN KEY (AlbumID) 
     REFERENCES Albums (AlbumID)) 

Une fois que vous avez cette conception, vous avez la possibilité de rechercher des albums individuels et des artistes ainsi que des chansons. Vous pouvez également ajouter des index de couverture pour accélérer les requêtes, et les index seront beaucoup plus petit et donc plus rapide que la conception originale.

Si vous n'avez pas besoin de faire des requêtes de plage (ce que vous n'avez probablement pas), vous pouvez remplacer la clé IDENTITY par une ROWGUID si cela convient mieux à votre conception; ce n'est pas vraiment important dans ce cas, je voudrais coller avec le simple IDENTITY.

Vous devez faire attention avec les clés de clustering. Si vous vous regroupez sur une touche qui n'est absolument pas séquentielle (et que l'artiste, l'album et le nom de la chanson sont définitivement non séquentiels), vous vous retrouvez avec des divisions de pages et d'autres comportements malveillants. Tu ne veux pas ça. Et comme Marc le dit, une copie de cette clé est ajoutée à chaque index, et vous ne voulez certainement pas cela lorsque votre clé est longue de 300 ou 600 octets.

Si vous voulez être en mesure d'interroger rapidement le nombre d'écoutes pour une chanson spécifique de l'artiste, l'album et le nom de la chanson, il est en fait assez simple avec la conception ci-dessus, vous avez juste besoin d'indexer correctement:

CREATE UNIQUE INDEX IX_Artists_Name ON Artists (ArtistName) 
CREATE UNIQUE INDEX IX_Albums_Artist_Name ON Albums (ArtistID, AlbumName) 
CREATE UNIQUE INDEX IX_Songs_Album_Name ON Songs (AlbumID, SongName) 
    INCLUDE (NumberOfListens) 

maintenant, cette requête sera rapide:

SELECT ArtistName, AlbumName, SongName, NumberOfListens 
FROM Artists ar 
INNER JOIN Albums al 
    ON al.ArtistID = ar.ArtistID 
INNER JOIN Songs s 
    ON s.AlbumID = al.AlbumID 
WHERE ar.ArtistName = @ArtistName 
AND al.AlbumName = @AlbumName 
AND s.SongName = @SongName 

Si vous consultez le plan d'exécution, vous verrez 3 index cherche - il est aussi rapide que vous pouvez l'obtenir. Nous avons garanti le même caractère unique que dans la conception originale et optimisé pour la vitesse. Plus important encore, il est normalisé, donc un artiste et un album ont chacun leur propre identité, ce qui facilite grandement la gestion à long terme. Il est beaucoup plus facile de rechercher "tous les albums de l'artiste X." beaucoup plus facile et plus rapide de rechercher" toutes les chansons sur l'album Y. "

Lors de la conception d'une base de données, la normalisation devrait être votre premier souci, l'indexation devrait être votre deuxième. Une fois que vous avez un design normalisé, la meilleure stratégie d'indexation devient un peu évidente

Questions connexes