sql >> Databáze >  >> RDS >> Sqlserver

Podpora UTF-8, SQL Server 2012 a UTF8String UDT

Vytvoření vlastního uživatelem definovaného typu pomocí SQLCLR není , jakýmkoliv způsobem vám zajistí náhradu jakéhokoli nativního typu. Je to velmi užitečné pro vytvoření něčeho, co zpracovává specializovaná data. Ale řetězce, byť s jiným kódováním, nejsou ani zdaleka specializované. Jít touto cestou pro data řetězců by zničilo jakékoli množství použitelnosti vašeho systému, nemluvě o výkonu, protože byste nemohli použít žádné vestavěné funkce řetězce.

Pokud byste byli schopni ušetřit cokoli na disku, tyto zisky by byly vymazány tím, co byste ztratili na celkovém výkonu. Uložení UDT se provádí jeho serializací do VARBINARY . Chcete-li tedy provést jakékoli porovnávání řetězců NEBO třídění, mimo "binární" / "ordinální" srovnání byste museli převést všechny ostatní hodnoty, jednu po druhé, zpět do UTF-8, abyste pak provedli porovnání řetězců, které může zohlednit lingvistické rozdíly. A ten převod by musel být proveden v rámci UDT. To znamená, že stejně jako datový typ XML byste vytvořili UDT, které by obsahovalo konkrétní hodnotu, a poté byste vystavili metodu tohoto UDT, aby přijala parametr řetězce za účelem porovnání (tj. Utf8String.Compare(alias.field1) nebo, pokud definujete operátor pro typ, pak Utf8string1 = Utf8string2 a mají = operátor získá řetězec v kódování UTF-8 a poté provede CompareInfo.Compare() ).

Kromě výše uvedených úvah je také třeba vzít v úvahu, že předávání hodnot tam a zpět přes SQLCLR API má své náklady, zejména při použití buď NVARCHAR(MAX) nebo VARBINARY(MAX) na rozdíl od NVARCHAR(1 - 4000) a VARBINARY(1 - 4000) respektive (nepleťte si prosím tento rozdíl jako naznačující cokoli o použití SqlChars / SqlBytes vs SqlString / SqlBinary ).

A konečně (alespoň pokud jde o použití UDT), nehledejte prosím na skutečnost, že dotazovaný UDT je ​​ukázkový kód . Jediné uvedené testování je čistě funkční, nic kolem škálovatelnosti nebo „lekce získané po roce práce s tímto“. Funkční testovací kód je zobrazen zde na následující stránce CodePlex a měli byste se na něj podívat, než budete pokračovat v tomto rozhodnutí, protože dává představu o tom, jak byste museli psát své dotazy, abyste s ním mohli komunikovat (což je v pořádku pro pole nebo dva, ale ne pro většinu / všechna pole řetězce):

http://msftengprodsamples.codeplex.com /SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Scripts/Test.sql

Bylo vzhledem k počtu přidaných trvalých vypočítaných sloupců a indexů skutečně ušetřeno nějaké místo?;-)

Pokud jde o prostor (disk, paměť atd.), máte tři možnosti:

  1. Pokud používáte SQL Server 2008 nebo novější a používáte Enterprise Edition, můžete povolit Komprese dat . Komprese dat může (ale nebude "vždy") komprimovat data Unicode v NCHAR a NVARCHAR pole. Určujícími faktory jsou:

    1. NCHAR(1 - 4000) a NVARCHAR(1 - 4000) použijte Standardní kompresní schéma pro Unicode , ale pouze počínaje SQL Server 2008 R2 A pouze pro data IN ROW, nikoli PŘETEČENÍ! Zdá se, že je to lepší než běžný kompresní algoritmus ROW / PAGE.
    2. NVARCHAR(MAX) a XML (a myslím, že také VARBINARY(MAX) , TEXT a NTEXT ) data, která jsou IN ROW (nikoli mimo řádek na stránkách LOB nebo OVERFLOW), mohou být komprimována alespoň PAGE a možná také ROW komprimovaný (tímto posledním si nejsem jistý).
    3. Jakákoli data OFF ROW, LOB nebo OVERLOW =žádná komprese pro vás!
  2. Pokud na Enterprise Edition používáte verzi starší než 2008 nebo ne, můžete mít dvě pole:jedno VARCHAR a jeden NVARCHAR . Řekněme například, že ukládáte adresy URL, které jsou většinou všechny základní znaky ASCII (hodnoty 0 – 127), a proto se hodí do VARCHAR , ale někdy mají znaky Unicode. Vaše schéma může obsahovat následující 3 pole:

      ...
      URLa VARCHAR(2048) NULL,
      URLu NVARCHAR(2048) NULL,
      URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
      CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
                        ([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
                    AND ([URLa] IS NULL OR [URLu] IS NULL))
    );
    

    V tomto modelu pouze VYBERTE z [URL] vypočítaný sloupec. Při vkládání a aktualizaci určujete, které pole se má použít, tím, že se podíváte, zda převod změní příchozí hodnotu, která musí být NVARCHAR typ:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Pokud máte pole, která by vždy měla obsahovat pouze znaky, které se vejdou do konkrétní kódové stránky rozšířené znakové sady ASCII, pak stačí použít VARCHAR .

P.S. Jen pro upřesnění:nový _SC Porovnání, která byla zavedena v SQL Server 2012, jednoduše umožňují:

  • vestavěné funkce pro správné zacházení s doplňkovými znaky / náhradními páry a
  • jazyková pravidla pro doplňkové znaky, která se používají pro řazení a porovnávání

Ale i bez nového _SC Porovnávání, stále můžete uložit jakýkoli znak Unicode do XML nebo N -typ s předponou a načtěte jej bez ztráty dat. Při použití starších kolací (tj. bez čísla verze v názvu) se však všechny doplňkové znaky shodují. Musíte použít _90 a _100 Porovnání, které vám alespoň umožní srovnání a třídění binárních / kódových bodů; nemohou brát v úvahu lingvistická pravidla, protože nemají žádná konkrétní mapování doplňkových znaků (a tudíž nemají žádné váhy ani pravidla normalizace).

Zkuste následující:

IF (N'𤪆' = N'𤪆') SELECT N'𤪆' AS [TheLiteral], NCHAR(150150) AS [Generated];
IF (N'𤪆' = N'𤪇') SELECT N'𤪇' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' COLLATE Tatar_90_CI_AI = N'𤪇' COLLATE Tatar_90_CI_AI)
       SELECT N'𤪇 COLLATE Tatar_90_CI_AI' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' = N'?') SELECT N'?';

V databázi s výchozím řazením končícím na _SC , pouze první IF příkaz vrátí sadu výsledků a pole "Generováno" zobrazí znaky správně.

Pokud však DB nemá výchozí řazení končící na _SC a řazení není _90 nebo _100 řazení řady, pak první dva IF příkazy vrátí sady výsledků, přičemž pole "Generováno" vrátí NULL a pole "Literal" se zobrazí správně.

U dat Unicode nemá řazení žádný vliv na fyzické úložiště.

AKTUALIZACE 2018-10-02

I když to zatím není schůdná možnost, SQL Server 2019 zavádí nativní podporu pro UTF-8 v VARCHAR / CHAR typy dat. V současné době je v něm příliš mnoho chyb na to, aby se dal použít, ale pokud jsou opraveny, pak je to pro některé možnost scénáře. Podívejte se prosím na můj příspěvek, "Nativní podpora UTF-8 v SQL Server 2019:Spasitel nebo Falešný prorok? “, pro podrobnou analýzu této nové funkce.




  1. Nejlepší způsob, jak provést víceřádkové vkládání v Oracle?

  2. Manipulace s uživatelskými daty v MySQL

  3. Jak vytvořit tabulku Postgres s jedinečným kombinovaným primárním klíčem?

  4. CTE vrací chybu