Jakie są najlepsze praktyki korzystania z GUID jako klucza podstawowego, w szczególności w odniesieniu do wydajności?

Mam aplikację, która używa GUID jako klucz podstawowy w prawie wszystkich tabelach i czytałem, że istnieją problemy dotyczące wydajności podczas korzystania z GUID jako klucz podstawowy. Szczerze mówiąc, nie widziałem żadnego problemu, ale mam zamiar uruchomić nową aplikację i nadal chcę używać GUID jako kluczy głównych, ale myślałem o użyciu kompozytowego klucza podstawowego (GUID i może inne pole.)

Używam GUID, ponieważ są ładne i łatwe do zarządzania, gdy masz inny środowiska takie jak bazy" produkcyjne"," testowe "i" dev" , a także migracja danych między bazami danych.

Użyję Entity Framework 4.3 i chcę przypisać Guid w kodzie aplikacji, przed wstawieniem go do bazy danych. (tzn. nie chcę, aby SQL generował Guid).

Jaka jest najlepsza praktyka tworzenia kluczy podstawowych opartych na GUID, aby uniknąć domniemanych uderzeń wydajności związanych z tym podejściem?

Author: abatishchev, 2012-08-13

5 answers

GUID może wydawać się naturalnym wyborem dla klucza podstawowego-a jeśli naprawdę musisz, prawdopodobnie możesz argumentować, że używasz go dla klucza podstawowego tabeli. To, co zdecydowanie zalecam , aby nie robić , to używanie kolumny GUID jako klucza klastrowego , co domyślnie robi SQL Server, chyba że wyraźnie mu tego nie nakazujesz.

Naprawdę trzeba trzymać dwa problemy z dala:

  1. Klucz podstawowy jest konstrukcją logiczną - jednym z kandydatów klawisze, które jednoznacznie i niezawodnie identyfikują każdy wiersz w tabeli. To może być wszystko, naprawdę - INT, GUID, ciąg-wybierz to, co ma największy sens dla Twojego scenariusza.

  2. Klucz klastrowy (kolumna lub kolumny, które definiują "indeks klastrowy" w tabeli)-jest to rzecz fizyczna związana z pamięcią masową, a tutaj mały, stabilny, stale rosnący typ danych jest najlepszym wyborem-INT lub BIGINT jako domyślna opcja.

By domyślnie klucz podstawowy w tabeli SQL Server jest również używany jako klucz klastrowania - ale nie musi tak być! Osobiście widziałem ogromny wzrost wydajności po rozbiciu poprzedniego klucza podstawowego / klastrowego opartego na GUID na dwa oddzielne klucze - klucz podstawowy (logiczny) na GUID i klucz klastrowania (zamawiania) na oddzielnej kolumnie INT IDENTITY(1,1).

Jako Kimberly Tripp - Królowa indeksowania - i inni stwierdzili wiele razy-a GUID jako klastra klucz nie jest optymalny, ponieważ ze względu na swoją losowość doprowadzi do ogromnej fragmentacji stron i indeksów oraz ogólnie złej wydajności.

Tak, Wiem - jest newsequentialid() W Sql Server 2005 i w górę - ale nawet to nie jest naprawdę i w pełni sekwencyjne, a zatem cierpi na te same problemy, co GUID - tylko trochę mniej widoczne.

Jest jeszcze jedna kwestia do rozważenia: klucz klastrowania na stole zostanie dodany do każdego wpisu na każdym niezaklustrowanym indeks na stole, jak również - więc naprawdę chcesz upewnić się, że jest tak mały, jak to możliwe. Zazwyczaj INT z 2+ miliardami wierszy powinien być wystarczający dla zdecydowanej większości tabel - a w porównaniu do GUID jako klucza klastrowania, możesz zaoszczędzić setki megabajtów pamięci na dysku i w pamięci serwera.

Szybkie obliczenia-użycie INT vs. GUID jako klucza podstawowego i klastrowego:

  • tabela bazowa z 1 ' 000 ' 000 wierszy (3,8 MB vs. 15,26 MB)
  • 6 indeksy niezakłócone (22.89 MB vs. 91.55 MB)

Razem: 25 MB vs. 106 MB - i to tylko na jednym stole!

Some more food for thought-excellent stuff by Kimberly Tripp-przeczytaj, przeczytaj jeszcze raz, przetraw! To indeksowanie serwera SQL.

PS: oczywiście, jeśli masz do czynienia z zaledwie kilkuset lub kilku tysięcy wierszy-większość z tych argumentów nie będzie miała większego wpływu na Ciebie. Jeśli jednak trafisz do dziesiątek, setek tysięcy wierszy, lub zaczniesz liczyć w milionach - wtedy te punkty stają się bardzo istotne i bardzo ważne dla Rozumiem.

Aktualizacja: jeśli chcesz mieć swoją kolumnę PKGUID jako klucz główny (ale nie klucz klastrowy), i inną kolumnę MYINT (INT IDENTITY) jako klucz do klastrowania-użyj tego:

CREATE TABLE dbo.MyTable
(PKGUID UNIQUEIDENTIFIER NOT NULL,
 MyINT INT IDENTITY(1,1) NOT NULL,
 .... add more columns as needed ...... )

ALTER TABLE dbo.MyTable
ADD CONSTRAINT PK_MyTable
PRIMARY KEY NONCLUSTERED (PKGUID)

CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT)

Zasadniczo: po prostu musisz jawnie powiedzieć PRIMARY KEY ograniczeniu, że jest to NONCLUSTERED (w przeciwnym razie jest tworzony jako twój klastrowy indeks, domyślnie) - a następnie tworzysz drugi indeks zdefiniowany jako CLUSTERED

To zadziała - i jest to prawidłowa opcja jeśli masz istniejący system, który wymaga "przeprojektowania" pod kątem wydajności. W przypadku nowego systemu, jeśli zaczniesz od zera, a nie jesteś w scenariuszu replikacji, zawsze wybrałbym ID INT IDENTITY(1,1) jako mój klastrowy klucz podstawowy-znacznie bardziej wydajny niż cokolwiek innego!

 415
Author: marc_s,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-13 16:59:39

Używam GUIDs jako PKs od 2005 roku. W tym rozproszonym świecie baz danych jest to absolutnie najlepszy sposób na scalanie rozproszonych danych. Możesz odpalić i zapomnieć o scalaniu tabel bez obaw o dopasowanie ints do połączonych tabel. Połączenia GUIDs można kopiować bez obaw.

To jest moja konfiguracja do korzystania z GUID:

  1. PK = GUID. GUID są indeksowane podobnie jak ciągi znaków, więc tabele wysokiego rzędu (ponad 50 milionów rekordów) mogą wymagać partycjonowania tabel lub innej wydajności techniki. SQL Server staje się niezwykle wydajny, więc problemy z wydajnością są coraz mniej odpowiednie.

  2. PK Guid jest indeksem Nieklastrycznym. Nigdy nie indeksuj GUID klastra, chyba że jest NewSequentialID. Ale nawet wtedy ponowne uruchomienie serwera spowoduje poważne przerwy w zamawianiu.

  3. Dodaj Clusterid Int do każdej tabeli. To jest Twój zbiorczy indeks...to zamówi Twój stolik.

  4. Dołączanie do ClusterIDs (int) jest bardziej efektywne, ale pracuję z 20-30 milionami rekordów tabel, więc łączenie na GUID nie ma widocznego wpływu na wydajność. Jeśli chcesz uzyskać maksymalną wydajność, użyj koncepcji ClusterID jako klucza podstawowego i dołącz do ClusterID.

Oto moja tabela e-mail...

CREATE TABLE [Core].[Email] (

[EmailID]      UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL,

[EmailAddress] NVARCHAR (50)    CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL,

[CreatedDate]  DATETIME         CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL,

[ClusterID] INT NOT NULL IDENTITY,
    CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC)
);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID])
GO

CREATE UNIQUE NonCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc)
 38
Author: Robert J. Good,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-31 21:27:41

Obecnie rozwijam aplikację internetową z EF Core i oto wzór, którego używam:

Wszystkie moje klasy (tabele) i int PK i FK. Mam dodatkową kolumnę o typie Guid (generowanym przez konstruktor c#) z nie klastrowym indeksem na niej.

Wszystkie połączenia tabeli w EF są zarządzane przez klucze int, podczas gdy cały dostęp z zewnątrz (Kontrolery) odbywa się za pomocą GUID.

To rozwiązanie pozwala nie pokazywać kluczy int na adresach URL, ale zachować model schludny i szybki.

 4
Author: EricImhauser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-12 08:14:15

Jeśli używasz GUID jako klucza podstawowego i tworzysz indeks klastrowy, sugeruję użycie domyślnej wartości NEWSEQUENTIALID ()

 3
Author: AnandPhadke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-13 16:47:42

Ten link mówi to lepiej niż mogłem i pomógł w podejmowaniu decyzji. Zazwyczaj wybieram int jako klucz podstawowy, chyba że mam określoną potrzebę, aby tego nie robić, a także pozwalam SQL server automatycznie generować/utrzymywać to pole, chyba że mam jakiś konkretny powód, aby tego nie robić. W rzeczywistości problemy z wydajnością muszą być określane na podstawie konkretnej aplikacji. Istnieje wiele czynników, w tym między innymi oczekiwany rozmiar db, odpowiednie indeksowanie, wydajne zapytania i wiele innych. Chociaż ludzie mogą nie zgadzam się, myślę, że w wielu scenariuszach nie zauważysz różnicy z obu opcji i należy wybrać, co jest bardziej odpowiednie dla aplikacji i co pozwala rozwijać łatwiej, szybciej i skuteczniej (jeśli nigdy nie ukończyć aplikację, co różnica robi reszta :).

Https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

P. S. Nie jestem pewien po co mielibyście używać PK kompozytowego czy jakie korzyści by Ci to dało.

 3
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-09 08:02:57