2010-08-10 13 views
5

Sto cercando di capire come il guid sequenziale funzioni meglio di un normale guid.Sequential Guid e frammentazione

È perché con guida regolare, l'indice utilizza l'ultimo byte del guid per ordinare? Dal momento che è casuale causerà un sacco di frammentazione e divisioni di pagina poiché spesso trasferirà i dati su un'altra pagina per inserire nuovi dati?

Guida sequenziale seno è sequenziale causerà un numero inferiore di divisioni e frammentazione della pagina?

La mia comprensione è corretta?

Se qualcuno può gettare più luci sull'argomento, lo apprezzerò molto.

Grazie

EDIT:

sequenziale guid = NEWSEQUENTIALID(),

guid regolare = NEWID()

+0

È possibile definire cosa si intende per "guida sequenziale" e in particolare "guida regolare". –

+2

@Greg: Credo che intenda un "guidale sequenziale" come generato da NEWSEQUENTIALID() rispetto a un "regolare guid" generato da NEWID() –

risposta

8

quali hai praticamente detto tutto nella sua interrogazione.

Con un GUID/chiave primaria sequenziale le nuove righe verranno aggiunte insieme alla fine della tabella, il che renderà le cose semplici e facili per il server SQL. In confronto una chiave primaria casuale significa che i nuovi record possono essere inseriti ovunque nella tabella - la possibilità che l'ultima pagina per la tabella sia nella cache è abbastanza probabile (se è lì che stanno andando tutte le letture), tuttavia la possibilità di una pagina casuale nel mezzo della tabella che si trova nella cache è piuttosto bassa, il che significa che è necessario un IO aggiuntivo.

Inoltre, quando si inseriscono le righe nel centro del tavolo, è possibile che non vi sia spazio sufficiente per inserire la riga aggiuntiva. In questo caso, il server SQL deve eseguire costose operazioni di I/O per creare spazio per la registrazione - l'unico modo per evitare ciò è di lasciare spazi vuoti tra i dati per consentire l'inserimento di ulteriori record (noto come Fattore di riempimento), che di per sé causa problemi di prestazioni perché i dati sono distribuiti su più pagine e quindi è necessario più IO per accedere all'intera tabella.

+0

Grazie! Volevo solo confermarmi di averlo capito correttamente. – pdiddy

2

Mi rimetto alla saggezza di Kimberly L. Tripp su questo argomento:

Ma, un GUID che non è sequenziale - come uno che h come è Valori generato nel client (utilizzando .NET) o generati dalla funzione newid() (in SQL Server) può essere un orribilmente cattiva scelta - principalmente a causa della frammentazione che si crea nella tabella di base ma anche a causa della sua dimensione . È largamente inutile (è 4 volte più largo di un'identità int-based - che può darti 2 miliardi (davvero 4 miliardi) di righe univoche). E, se hai bisogno di più di 2 miliardi di tu puoi sempre andare con un bigint (8 byte int) e ottenere 263-1 righe.

Per saperne di più: http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx#ixzz0wDK6cece

+0

Con Sequential Guid, poiché è sequenziale, tecnicamente tutte le nuove pagine indice saranno in teoria sequenziali migliorando così le prestazioni. Sto capendo correttamente? Per guida regolare, i record saranno dappertutto poiché è casuale, quindi fare una scelta regolare con un intervallo può essere lento? – pdiddy

+0

@pdiddy: visto che i GUID "casuali" non sono sequenziali, perché dovresti selezionare per un intervallo di essi? – JNK

+2

Sei corretto sulla natura sequenziale o casuale, tuttavia il vero dolore è su INSERT piuttosto che su SELECT. –

0

Per visualizzare l'intera immagine è possibile utilizzare util named ostress. E.g.è possibile creare due tabelle: una con normale GUID come PK, un altro con sequenziale GUID:

-- normal one 
CREATE TABLE dbo.YourTable(
    [id] [uniqueidentifier] NOT NULL, 
    CONSTRAINT [PK_YourTable] PRIMARY KEY NONCLUSTERED (id) 
); 
-- sequential one 
CREATE TABLE dbo.YourTableSeq(
    [id] [uniqueidentifier] NOT NULL CONSTRAINT [df_yourtable_id] DEFAULT (newsequentialid()), 
    CONSTRAINT [PK_YourTableSeq] PRIMARY KEY NONCLUSTERED (id) 
); 

Poi, con un dato util si esegue un numbero di inserti con la selezione di statistiche su indice di frammentazione:

ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTable VALUES (NEWID()); SELECT count(*) AS Cnt FROM dbo.YourTable; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTable';" -oE:\incoming\TMP\ -n1 -r10000 

ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTableSeq DEFAULT VALUES; SELECT count(*) AS Cnt FROM dbo.YourTableSeq; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTableSeq';" -oE:\incoming\TMP\ -n1 -r10000 

Quindi nel file E: \ incoming \ TMP \ query.out troverete le vostre statistiche. I miei risultati sono i seguenti:

"Normal" GUID: 
Records AvgPageFragmentation  PageCounts   
---------------------------------------------- 
1000  87.5      8      
2000  93.75     16     
3000  96.15384615384616  26     
4000  96.875     32     
5000  96.969696969696969  33     
10000  98.571428571428584  70     


Sequential GUID: 
Records AvgPageFragmentation  PageCounts   
---------------------------------------------- 
1000  83.333333333333343  6      
2000  63.636363636363633  11     
3000  41.17647058823529  17     
4000  31.818181818181817  22     
5000  25.0      28     
10000  12.727272727272727  55  

Come si può vedere con sequenza generata GUID viene inserito, l'indice è molto meno frammentato come l'operazione di inserimento porta alla nuova allocazione più rari pagina.