Vítejte na blog.vyvojar.cz Přihlásit | Registrovat | Pomoc

Zdeněk Drlík

Vývoj aplikací, platforma .NET a další ...
Sekvenční GUID

Při návrhu sloupců primárních klíčů se u MS SQL poměrně často používá datový typ GUID. Jednou ze zajímavých výhod tohoto datového typu pro aplikačního vývojáře je fakt, že hodnoty primárních klíčů je možné generovat i v klientské aplikaci (standardně metodou Guid.NewGuid()). Odpadá tak určitá pracnost navíc při použití databází generovaných sekvenčních hodnot klíče (INT s IDENTITY apod.), kdy je nutné po vložení záznamu hodnoty z databáze do aplikace zpětně načítat. Z pohledu vývojáře je tedy GUID většinou méně pracné řešení a proto bývá také často jako primární klíč používán.

Pro databázový server nicméně primární klíče s datovým type GUID není úplně ideální volba. Datový typ GUID zabírá jednak o něco víc místa než například zmiňovaný INT (16 byte GUID oproti 4 byte INT). Díky tomu budou například databázové indexy s použitím GUID vždy větší, než indexy s použitím INT.

Možná ještě větším problémem může být skutečnost, že generovaná hodnota je z pohledu řazení náhodná. Ve spojení s primárním klíčem a navíc clustered indexem (pokud není explicitně řečeno jinak, je vytvářen s primárním klíčem “by default”) dochází tedy většinou k tomu, že nově vkládaný záznam není ukládán jako u sekvenčních hodnot v tabulce “na konec”, ale do různých datových stránek podle vygenerované hodnoty. Toto vede k častější nutnosti rozdělování stránek a reorganizaci dat v nich (blíže viz popis u Fill Factor). Výsledkem je obvykle daleko vyšší počet použitých stránek a také jejich vyšší fragmentace, než při použití klíčů se sekvenčně generovanými hodnotami.

Jedním z řešení, které dokáže tuto nevýhodu eliminovat, je generování sekvenčních GUID. Jedná se o způsob generování GUID, který zajišťuje, že hodnoty generované na jednom počítači budou jednak unikátní a také každá vytvořená hodnota bude větší než předchozí.

V databázi pro tento způsob vytváření lze využít funkci NEWSEQUENTIALID (bohužel lze využít pouze jako default hodnota sloupce), možnost generování takovéto hodnoty v aplikaci je ukázáno dále.

Vytváření sekvenčního GUID v .NET

Pro vytvoření sekvenčního GUID existuje API funkce UuidCreateSequential. Protože managed třída Guid metody pro její využití neobsahuje, je nutné toto implementovat s pomocí P/Invoke voláním této API funkce. Pomocnou třídu pro jejich vytváření nazveme například GuidCreator a vypadat by mohla například takto:

Code Snippet
  1. public static class GuidCreator
  2. {        
  3.     private enum RpcUuidCodes : int
  4.     {
  5.         RPC_S_OK = 0,
  6.         RPC_S_UUID_LOCAL_ONLY = 1824,
  7.         RPC_S_UUID_NO_ADDRESS = 1739
  8.     }
  9.     [System.Runtime.InteropServices.DllImport("rpcrt4.dll", SetLastError = true)]
  10.     static extern int UuidCreateSequential(out Guid guid);      
  11.         
  12.     public static Guid NewGuid()
  13.     {
  14.         return Guid.NewGuid();
  15.     }
  16.     public static Guid NewSequentialGuid()
  17.     {
  18.         return CreateSequentialGuid();
  19.     }
  20.     public static Guid NewSQLSequentialGuid()
  21.     {
  22.         return SQLLikeReverseBytes(CreateSequentialGuid());
  23.     }
  24.         
  25.     private static Guid CreateSequentialGuid()
  26.     {
  27.         Guid guid = Guid.Empty;
  28.         var resultCode = UuidCreateSequential(out guid);
  29.         switch (resultCode)
  30.         {
  31.             case (int)RpcUuidCodes.RPC_S_OK:
  32.                 break;
  33.             case (int)RpcUuidCodes.RPC_S_UUID_LOCAL_ONLY:
  34.                 throw new Exception(@"NewGuid failed - UuidCreateSequential returned RPC_S_UUID_LOCAL_ONLY");
  35.             case (int)RpcUuidCodes.RPC_S_UUID_NO_ADDRESS:
  36.                 throw new Exception(@"NewGuid failed - UuidCreateSequential returned RPC_S_UUID_NO_ADDRESS");
  37.             default:
  38.                 throw new Exception(String.Format(@"NewGuid failed - UuidCreateSequential returned {0}", resultCode));
  39.         }
  40.         return guid;
  41.     }
  42.     private static Guid SQLLikeReverseBytes(Guid value)
  43.     {
  44.         var bytes = value.ToByteArray();
  45.         Array.Reverse(bytes, 0, 4);
  46.         Array.Reverse(bytes, 4, 2);
  47.         Array.Reverse(bytes, 6, 2);
  48.         return new Guid(bytes); ;
  49.     }        
  50. }

Metoda NewGuid je zde uvedena jen pro úplnost a reprezentuje klasické vytváření náhodného GUID pomocí volání standardní .NET metody Guid.NewGuid(). Hodnoty jsou generovány náhodně:

965bb964-6eca-4607-a037-d2550b51aefa
6f7d260a-67b3-444b-a7e7-dba8fddcd7a6
1fecc9c7-50a7-4f78-99cc-469a8cf65fc4
7fbde154-be15-469a-8d91-c337b9d1c37a

Metoda NewSequentialGuid reprezentuje vytváření sekvenčního GUID pomocí přímého volání API funkce UuidCreateSequential:

b5aea086-aecc-11df-940d-001fe2e4f119
b5aea087-aecc-11df-940d-001fe2e4f119
bd77004c-aecc-11df-940d-001fe2e4f119
bd77004d-aecc-11df-940d-001fe2e4f119

Pro kompatibilitu s SQL metodou NEWSEQUENTIALID je potřeba ještě ve vygenerovaném GUID provést přehození některých bytů. Dle http://blogs.msdn.com/b/sqlprogrammability/archive/2006/03/23/559061.aspx se přehození provádí proto, aby výsledné hodnoty lépe vyhovovaly interním algoritmům SQL serveru pro porovnávání GUID hodnot. Tento postup implementuje metoda NewSQLSequentialGuid a generované hodnoty tak odpovídají hodnotám vraceným uvedenou SQL funkcí:

6cd9ef0e-cdae-df11-940d-001fe2e4f119
6dd9ef0e-cdae-df11-940d-001fe2e4f119
4ab28917-cdae-df11-940d-001fe2e4f119
4bb28917-cdae-df11-940d-001fe2e4f119

V případě použití takto generovaných hodnot je samozřejmě dobré si uvědomit, že sekvenčně generované budou hodnoty vždy pouze na jednom počítači. Lze to tedy použít u aplikací, u nichž lze toto zajistit (ASP.NET, vícevrstvé aplikace s aplikačním serverem apod.). V klientských aplikacích bez aplikačního serveru postrádá většinou použití sekvenčních ID smysl.

Testovací aplikace s příkladem generování hodnot pomocí výše uvedené třídy GuidCreator je k dispozici ke stažení zde.

Na závěr ještě pár odkazů na další informace:

http://msdn.microsoft.com/en-us/library/ms190215.aspx

http://www.mssqltips.com/tip.asp?tip=1600

http://www.jorriss.net/blog/jorriss/archive/2008/04/24/unraveling-the-mysteries-of-newsequentialid.aspx 

http://www.shirmanov.com/2010/05/generating-newsequentialid-compatible.html

Posted: Tuesday, August 24, 2010 7:10 AM by zdenek.drlik
Vedeno pod: ,

Komentář

vlko napsal:

# August 24, 2010 9:13 AM

Petr napsal:

A není lepší tedy namísto generování sekvenčních GUIDů přidat sloupec s IDENTITY a nad ním vytvořit clustered index? Takto mi přijde, že vznikne hybridní řešení nevýhodné jak z pohledu DB (index prostě vetší bude) tak z pohledu použití GUIDu jako unikátního identifikátoru - unikátnost je řádově snížena a je to nepoužitelné např. pro synchronizaci dvou dat. zdrojů. Takže v tomto řešení nevidím žádný výhodu.

# August 24, 2010 10:06 AM

zdenek.drlik napsal:

Sloupec s IDENTITY bude z pohledu velikosti indexu vždy výhodnější, to je bez diskuze.

Nicméně unikátnost sekvenčně generovaných GUID podle mě snížena nijak není (za předpokladu, že počítač má síťovou kartu - viz popis API funkce UuidCreateSequential) a pokud už někdo chce GUID použít jako primární klíč, tak je to z pohledu DB lepší varianta než náhodný GUID.

# August 24, 2010 10:27 AM

vlko napsal:

Algoritmus generujuci GUID na zaklade MAC adresy sietovej karty sa uz nepouziva z dvoch dovodov. 1. je mozne vystopovat, kto vytvoril GUID a 2. v dnesnej dobe nie je problem zmenit MAC adresu a tak mozu vznikat kolizie, inak aj vyrobcom sa uz stava, ze reusuju stare mac adresy. Tomuto algoritmu sa hovori GUID v1. V .net sa uz ale pouziva v4, obe tieto verzie su identifikovatelne pomocou cisla v guid vid http://en.wikipedia.org/wiki/Globally_Unique_Identifier#Algorithm

# August 24, 2010 11:25 AM

Petr napsal:

Jak píše vlko MAC se pro generování GUIDu nepoužívá. Osobně jsem nemyslel použití IDENTITY jako primárního klíče, ale pouze jako hodnoty pro clustered index a jako primární klíč používat unikátní nesekvenční GUIDy. Snížení unikátnosti vidím v souvislé řadě, kde ač její počátek je náhodný, každá následující hodnota již náhodná není (tzn. může dojít k prolnutí dvou řad při dostatečném počtu hodnot). Dle mě je tím pádem generace unikátní hodnoty zajištěna jen pro první, ostatní jsou již totéž co IDENTITY (inkrement).

# August 24, 2010 12:07 PM

zdenek.drlik napsal:

SQL funkce NEWSEQUENTIALID interně využívá API funkci UuidCreateSequential :

NEWSEQUENTIALID is a wrapper over the Windows UuidCreateSequential function.

a tato podle popisu používá pro generování onen "už nepoužívaný" algoritmus založený na MAC adrese.

Pokud tomu tak je, tak pak tedy příliš nerozumím tomu, proč tuto funkci MS v SQL 2005 představil a doporučuje ji právě používat ve scénářích kdy GUID je použit jako primární klíč.

# August 24, 2010 12:25 PM

Petr napsal:

Proč je tato technika doporučována a je podporována MS je mi také záhadou, protože na sekvenčním GUIDu nevidím jedinou výhodu (vyjma potlačení fragmentace datových bloků při insertech). Fragmentaci se ovšem dá zamezit použitím IDENTITY jen pro clusterovaný index (v business vrstvě se nemusí vůbec uplatnit) a pro primární klíč je užit standardní náhodný GUID se všemi jeho výhodami (unikátnost v čase/prostoru). Podle mě není sekvenční GUID nic jiného než větší IDENTITY s náhodnou počáteční hodnotou a to mi přijde příliš málo vzhledem k dalším vlastnostem (velikost, rychlost hledání). Navíc riziko kolize se dle mého řádově zvýší (je-li Guid1 = {a1...} a Guid2 = {af...} je otázkou kolize vložení pouhých 15 hodnot. Při standardním GUIDu to na pravděpodobnost kolize nemá vliv)

# August 24, 2010 12:40 PM

vlko napsal:

Dovod preco bol sequencny quid odporucany pre index je jednoduchy. Nahodny guid sa proste pri castych insert operaciach do bstromu nehodi, pretoze prave jeho nahodnost vedie k castemu vyvazovaniu stromu a tym degraduje vykon narozdiel od increment primary klucov (ak uz degradaciou nie je velkost guid vs int:). Vid napr: http://sqlblogcasts.com/blogs/martinbell/archive/2009/05/25/GUID-Fragmentation-in-SQL-Server.aspx

Ja osobne by som si uz ale int ako kluc nevybral ani za svet, guid mi vela krat zachranil kozu najma pri rozhodnuti sa zakaznika, ze je potreba replikovat. Urcite ale su tu riesenia, kde je performance tym najvyssim top ukazovatelom a tam su guidy neprechodne. To ale ide aj pri guidoch riesit shardingom na ORM vrstve, pretoze sebelepsi sql stroj je stale jednym fyzicky uzkym hradlom aplikacie (BTW to je aj dovod, preco je v poslednej dobe tolko buzzu okolo nosql).

# August 24, 2010 1:00 PM

rob napsal:

Nic neni cernobile.

1) Clustered index nemusi byt zadny index. Na co tedy fake IDENTITY?

2) Clustered index ma smysl pro dotazovani na hodnoty od-do (nebo treba pro strankovani). Primarni klic (at uz IDENTITY nebo GUID) temer nikdy neni takto dotazovan. Spise to je vhodne pro dotazovani pres datum nebo nejake cislo dokladu apod.

3) Sekvencni klice primarniho indexu mohou vest ke konkurenci (deadlock) na posledni strance (popr. v odpovidajici casti indexu) kam se defakto vkladaji vsechny nove zaznamy. Pro intenzivni vkladani se to tedy take ne uplne hodi.

# August 26, 2010 3:04 PM

Daniel Steigerwald napsal:

Sekvenční guidy sajou. Nedávno se chytil Ayende na RavendDB. Guidy jsou sekvenční, dokud nerestartujete komp.

# September 10, 2010 1:46 AM

roll forming machine napsal:

sekvencne guidy generuje aj nhibernate (bez managed kodu):

# July 16, 2011 12:31 PM

roll former napsal:

Proč je tato technika doporučována a je podporována MS je mi také záhadou, protože na sekvenčním GUIDu nevidím jedinou výhodu (vyjma potlačení fragmentace datových bloků při insertech). Fragmentaci se ovšem dá zamezit použitím IDENTITY jen pro clusterovaný index (v business vrstvě se nemusí vůbec uplatnit) a pro primární klíč je užit standardní náhodný GUID se všemi jeho výhodami (unikátnost v čase/prostoru). Podle mě není sekvenční GUID nic jiného než větší IDENTITY s náhodnou počáteční hodnotou a to mi přijde příliš málo vzhledem k dalším vlastnostem (velikost, rychlost hledání). Navíc riziko kolize se dle mého řádově zvýší (je-li Guid1 = {a1...} a Guid2 = {af...} je otázkou kolize vložení pouhých 15 hodnot. Při standardním GUIDu to na pravděpodobnost kolize nemá vliv)<A href="http://www.hyairfiltration.com/" target=_blank>roll forming</A>, <A href="http://www.hyairfiltration.com/" target=_blank>rollform</A>, <A href="http://www.hyairfiltration.com/" target=_blank>rollforming</A>,

# July 16, 2011 12:32 PM

wedding dresses desgins napsal:

Beautiful wedding dresses are on sale.I think you will find the dresses you like.

<a href ="http://www.iweddingdressshop.com/25-column-wedding-dresses">column wedding dresses</a>

Here,you also can see some other style dresses,for example,

<a href ="http://www.iweddingdressshop.com/21-a-line-wedding-dresses">a line wedding dresses</a>

# July 26, 2011 7:25 AM

Tiffany Earrings napsal:

Tiffany silver charms are hot now, especially the Letter Lock Charms. It is popular to choose the letters that symbolize your name or whose name that you shopping for as a perfect gift. You can also choose charms to match your bracelets, chains and your handbags.

# September 6, 2011 7:52 AM

cheap wedding dress napsal:

this is good

# September 27, 2011 11:56 AM

ugg boots napsal:

i like this post

# October 20, 2011 11:16 AM

gugo321@126.com napsal:

Merrell has easy wearing and casual sandals, such as the Merrell Glade, Merrell Aster, and Merrell Pansy.A fusion of latest design, comfort and proven performance since they are, Merrell footwear are thus the high quality MBT Shoes that attract outdoor enthusiasts. Merrell's philosophy draws on the concept that outdoor adventures give you a greater a sense of freedom, self-awareness, and fulfillment.

<strong><a href="http://www.mbtsandalsdiscount.com/" title="MBT Sandals" >MBT Sandals</a></strong>

<strong><a href="http://www.mbtsandalsdiscount.com/" title="MBT Sandals Clearance" >MBT Sandals Clearance</a></strong>

# November 12, 2011 6:04 AM

discount karen millen napsal:

Karen Millen ensemble departs the greatest <a href="http://www.karenmillen2.com" title="discount karen millen"><strong>discount karen millen</strong></a> affect around the nearly all wonderful evening??All in this causes it to become one of the best put on <a href="http://www.karenmillen2.com/karen-millen-one-shoulder-dress-c-3.html" title="karen millen one shoulder dress"><strong>karen millen one shoulder dress</strong></a> to look ahead of time with regards to prom. Darker promenade Nancy kitty0208lin Millen Great Tone wedding gown leaves behind the most affect <a href="http://www.karenmillen2.com/satin-karen-millen-cocktail-party-dress-red-dl025-p-39.html" title="karen millen red dress"><strong>karen millen red dress</strong></a> about the most stunning night time.

# February 8, 2012 9:14 AM

Bittu napsal:

Reading more today on the hiusong market.  Some think it still will drop another 20%.  I agree that it will continue to drop 10% and more depending on the market.What do you think?

# February 26, 2012 1:02 PM

dtkmzj napsal:

# February 27, 2012 12:36 PM

hoaldm napsal:

WgBocp , [url=http://rmjqdpezgdcm.com/]rmjqdpezgdcm[/url], [link=http://eynpyuqxmgvk.com/]eynpyuqxmgvk[/link], http://nopyjrtuqhzv.com/

# February 27, 2012 5:34 PM

tbtanor napsal:

# March 1, 2012 2:54 PM

djmlmputcuh napsal:

ad9DXv , [url=http://usmtkkcaeazb.com/]usmtkkcaeazb[/url], [link=http://jupsfipchyum.com/]jupsfipchyum[/link], http://kaovmllmnxpx.com/

# March 13, 2012 11:44 PM

khlnntpkbb napsal:

TedKcs , [url=http://ynxuzhnvsdua.com/]ynxuzhnvsdua[/url], [link=http://pggjaqfhcxvn.com/]pggjaqfhcxvn[/link], http://xxopofkxrfsk.com/

# March 13, 2012 11:45 PM
Vytvoření nového komentáře

(povinný) 

(povinný) 

(nepovinný)

(povinný) 

Opiš čísla, která vidíš na obrázku:

Upozornění na nové komentáře

Pokud chčeš dostávat upozornění emailem na změny u toho příspěvku,tak se zaregistruj zde.zde

Odebírat komentáře k tomuto příspěvku pomocí RSS