Jsme uprostřed cyklu mezi vydáními, kde ještě neslyšíme o žádné z plánovaných funkcí SQL Server vNext. Toto je pravděpodobně nejlepší čas tlačit Microsoft na vylepšení, pokud můžeme naše požadavky podpořit legitimními obchodními případy. V SQL Server 2016 STRING_SPLIT
vyřešil dlouho chybějící mezeru v jazyce, který, pravda, nebyl určen pro složité zpracování řetězců. A to je to, o čem chci dnes mluvit.
Roky před SQL Serverem 2016 (a roky poté) jsme psali vlastní verze, časem je vylepšovali a dokonce jsme se hádali, která je nejrychlejší. Blogovali jsme o každé mikrosekundě, kterou jsme mohli získat, a já jsem například několikrát prohlásil:"Toto je můj poslední příspěvek o dělení strun!" Přesto jsme tady.
Vždy budu tvrdit, že tabulkové parametry jsou tím správným způsobem, jak rozdělit řetězce. Ale zatímco já věřím, že tyto čárkami oddělené bloby textu by nikdy neměly být vystaveny databázi v této podobě, dělení řetězců je i nadále převládajícím případem použití – několik mých blogových příspěvků zde je v top 5 v zobrazení každý den .
Proč se tedy lidé stále snaží rozdělit řetězce pomocí funkcí s hodnotou tabulky, když existuje lepší náhrada? Některé, jsem si jistý, protože jsou stále na starších verzích, uvízly na starší úrovni kompatibility nebo se vůbec nemohou zbavit rozdělování řetězců, protože TVP nejsou podporovány jejich jazykem nebo ORM. Pro zbytek, zatímco STRING_SPLIT
je pohodlné a efektivní, není dokonalé. Má omezení, která s sebou nesou určité tření a kvůli kterým je nahrazení stávajících volání funkcí nativním voláním těžkopádné nebo nemožné.
Zde je můj seznam.
Tato omezení nejsou vyčerpávající, ale ty důležité jsem uvedl v moji pořadí priority (a Andy Mallon o tom dnes také blogoval):
- Jednoznakový oddělovač
Zdá se, že funkce byla vytvořena pouze s ohledem na zcela jednoduchý případ použití:CSV. Lidé mají složitější řetězce než1,2,3
neboA|B|C
a často jsou do svých databází přiváděny ze systémů mimo jejich kontrolu. Jak popisuji v této odpovědi a v tomto tipu, existují způsoby, jak to obejít (opravdu neefektivní operace nahrazení), ale jsou opravdu ošklivé a upřímně řečeno, ruší všechny výhody výkonu, které nabízí nativní implementace. Některá tření s tímto se také konkrétně týká:„No,string_to_array
PostgreSQL zvládá více oddělovačů znaků, tak proč by nemohl SQL Server?" Implementace:Zvětšete maximální velikostseparator
. - Žádné označení vstupního pořadí
Výstupem funkce je množina a množiny ve své podstatě nemají pořadí. A zatímco ve většině případů uvidíte vstupní řetězec jakobob,ted,frank
vyjdou v tomto pořadí (bob
ted
frank
), neexistuje žádná záruka (s nebo bez nedbalého(ORDER BY (SELECT NULL))
zaseknout). Mnoho podomácku vytvořených funkcí obsahuje výstupní sloupec k označení pořadové pozice v řetězci, což může být důležité, pokud je seznam uspořádán v definovaném pořadí nebo má přesná pořadová pozice určitý význam. Implementace:Přidejte možnost zahrnout sloupec pořadové pozice do výstup. - Typ výstupu je založen pouze na vstupu
Výstupní sloupec funkce je pevně nastaven navarchar
nebonvarchar
a je určeno přesně délkou celého vstupního řetězce, nikoli délkou nejdelšího prvku. Takže máte seznam 25 písmen, typ výstupu je nejméněvarchar(51)
. U delších řetězců to může vést k problémům s přidělením paměti v závislosti na využití a může způsobit problémy, pokud se spotřebitel spoléhá na jiný typ dat, který je na výstupu (řekněmeint
, které funkce někdy specifikují, aby se později vyhnuly implicitním převodům). Jako řešení mohou uživatelé někdy vytvořit své vlastní dočasné tabulky nebo proměnné tabulky a před interakcí s ní vypsat výstup funkce, což může vést k problémům s výkonem. Implementace:Přidejte možnost k určení typu výstupuvalue
. - Nelze ignorovat prázdné prvky nebo koncové oddělovače
Když máte řetězec jakoa,,,b,
, můžete očekávat, že budou na výstupu pouze dva prvky, protože ostatní tři jsou prázdné. Většina vlastních TVF, které jsem viděl, ořezává koncové oddělovače a/nebo odfiltruje řetězce nulové délky, aleSTRING_SPLIT
vrátí všech 5 řádků. To ztěžuje záměnu v nativní funkci, protože k odstranění těchto entit musíte také přidat logiku balení. Implementace:Přidejte možnost ignorovat prázdné prvky. - Nelze filtrovat duplikáty
Toto je pravděpodobně méně častý požadavek a lze jej snadno vyřešit pomocíDISTINCT
neboGROUP BY
, ale mnoho funkcí to dělá automaticky za vás. V těchto případech není žádný skutečný rozdíl ve výkonu, ale existuje, pokud je to něco, co zapomenete přidat (předpokládejte velký seznam se spoustou duplikátů, spojení do velké tabulky). Implementace:Přidejte možnost filtrování duplikátů.
Zde je obchodní případ.
To vše zní teoreticky, ale zde je obchodní případ, o kterém vás mohu ujistit, že je velmi skutečný. Ve Wayfair máme značné množství SQL Serveru a máme doslova desítky různých týmů, které si v průběhu let vytvořily své vlastní tabulkové funkce. Některé jsou lepší než jiné, ale všechny jsou volány z tisíců a tisíců řádků kódu. Nedávno jsme zahájili projekt, kde se je snažíme nahradit voláním STRING_SPLIT
, ale narazili jsme na případy blokování zahrnující několik výše uvedených omezení.
Některé lze snadno obejít pomocí funkce wrapper. Ale jeden oddělovač znaků omezení nás donutilo vyhodnotit příšerné řešení pomocí REPLACE
a ukázalo se, že to eliminovalo výkonnostní přínos, který jsme očekávali, a přimělo nás pumpovat brzdy. A v těchto případech jsme ztratili klíčový vyjednávací čip při prosazování upgradů na úroveň kompatibility (ne všechny databáze jsou na 130, nemluvě na 140). V těchto případech ztrácíme nejen na STRING_SPLIT
vylepšení, ale také dalších 130+ vylepšení výkonu, která bychom si užili, kdyby STRING_SPLIT
byla sama o sobě dostatečně přesvědčivá, aby prosadila upgrade na úrovni compat.
Prosím tedy o vaši pomoc.
Navštivte prosím tuto položku zpětné vazby:
- STRING_SPLIT není dokončena
Hlasujte! Ještě důležitější je, zanechat komentář popisující skutečné případy použití, které máte a které vytvářejí STRING_SPLIT
bolest nebo non-startér pro vás. Samotné hlasy nestačí, ale s dostatkem hmatatelné a kvalitativní zpětné vazby existuje šance, že začnou brát tyto mezery vážně.
Mám chuť podporovat víceznakové oddělovače (dokonce i, řekněme, rozšíření z [n]varchar(1)
na [n]varchar(5)
) je nenápadné vylepšení, které odblokuje mnoho lidí, kteří sdílejí můj scénář. Další vylepšení může být obtížnější implementovat, některá vyžadují přetížení a/nebo jazyková vylepšení, takže neočekávám všechny tyto opravy ve vNext. Ale i jedno malé vylepšení by zopakovalo, že STRING_SPLIT
byla investice, která se vyplatila, a že nebude opuštěna (např. databáze s obsahem, jedna z nejznámějších funkcí drive-by).
Děkujeme za poslech!