Vi är mitt i cykeln mellan releaser, där vi ännu inte hör om någon av funktionerna som planeras för SQL Server vNext. Detta är förmodligen den bästa tiden att trycka på Microsoft för förbättringar, så länge vi kan backa upp våra förfrågningar med legitima affärsfall. I SQL Server 2016, STRING_SPLIT
löste en sedan länge saknad lucka i ett språk som visserligen inte var avsett för komplicerad strängbearbetning. Och det är vad jag vill ta upp idag.
I åratal före SQL Server 2016 (och i flera år sedan) har vi skrivit våra egna versioner, förbättrat dem över tiden och till och med bråkat om vem som var snabbast. Vi bloggade om varje mikrosekund vi kunde vinna och jag, för en, har sagt flera gånger, "det här är mitt sista inlägg om att dela strängar!" Men här är vi.
Jag kommer alltid att hävda att tabellvärdade parametrar är det rätta sättet att bryta isär strängar. Men medan jag Jag tror att dessa kommaseparerade textklumpar aldrig bör exponeras för databasen i den formen, dela strängar fortsätter att vara ett utbrett användningsfall - ett par av mina blogginlägg här är bland de fem bästa i visningar varje dag .
Så varför försöker folk fortfarande dela strängar med tabellvärderade funktioner när det finns en överlägsen ersättning? Vissa, jag är säker på, eftersom de fortfarande finns på äldre versioner, har fastnat i en äldre kompatibilitetsnivå eller inte kan komma ifrån att dela strängar alls eftersom TVP:er inte stöds av deras språk eller ORM. För resten, medan STRING_SPLIT
är både bekvämt och effektivt, det är inte perfekt. Den har restriktioner som medför en viss friktion och som gör det krångligt eller omöjligt att ersätta befintliga funktionsanrop med ett inbyggt anrop.
Här är min lista.
Dessa begränsningar är inte uttömmande, men jag har listat de viktiga i min prioritetsordning (och Andy Mallon bloggade om detta idag också):
- Enkelteckenavgränsare
Det verkar som om funktionen har skapats med endast det döda enkla användningsfallet i åtanke:CSV. Människor har mer komplexa strängar än1,2,3
ellerA|B|C
, och de matas ofta till sina databaser från system utanför deras kontroll. Som jag beskriver i det här svaret och det här tipset finns det sätt att kringgå detta (verkligen ineffektiva ersättningsoperationer), men de är riktigt fula och, helt ärligt, ångrar alla prestandafördelar som erbjuds av den inbyggda implementeringen. En del av friktionen med den här kommer också specifikt ner på:"Tja, PostgreSQL:sstring_to_array
hanterar flera teckenavgränsare, så varför kan inte SQL Server?" Implementering:Öka maxstorleken påseparator
. - Ingen indikation på inmatningsordning
Funktionens utdata är en uppsättning och i sig har uppsättningar ingen ordning. Och medan du i de flesta fall kommer att se en inmatningssträng sombob,ted,frank
komma ut i den ordningen (bob
ted
frank
), finns det ingen garanti (med eller utan en slarvig(ORDER BY (SELECT NULL))
hacka). Många hemmabyggda funktioner inkluderar en utdatakolumn för att indikera ordningspositionen i strängen, vilket kan vara viktigt om listan är ordnad i en definierad ordning eller exakt ordningsposition har någon betydelse. Implementering:Lägg till ett alternativ för att inkludera kolumn för ordningsposition i utgången. - Utdatatyp baseras endast på indata
Utdatakolumnen för funktionen är fixerad till antingenvarchar
ellernvarchar
, och bestäms exakt av längden på hela inmatningssträngen, inte längden på det längsta elementet. Så du har en lista med 25 bokstäver, utdatatypen är minstvarchar(51)
. För längre strängar kan detta rinna ner till problem med minnesbidrag, beroende på användning, och kan skapa problem om konsumenten förlitar sig på att en annan datatyp matas ut (säg,int
, vilka funktioner ibland anger för att undvika implicita konverteringar senare). Som en lösning skapar användare ibland sina egna temporära tabeller eller tabellvariabler och dumpar utdata från funktionen där innan de interagerar med den, vilket kan leda till prestandaproblem.Implementering:Lägg till ett alternativ för att specificera utdatatypen förvalue
. - Kan inte ignorera tomma element eller efterföljande avgränsare
När du har en sträng soma,,,b,
, kan du förvänta dig att endast två element matas ut, eftersom de andra tre är tomma. De flesta anpassade TVF:er jag har sett trimma av efterföljande avgränsare och/eller filtrera bort nolllängda strängar, menSTRING_SPLIT
returnerar alla 5 raderna. Detta gör det svårt att byta i den inbyggda funktionen eftersom du också måste lägga till omslutningslogik för att eliminera dessa entiteter. Implementering:Lägg till ett alternativ för att ignorera tomma element. - Kan inte filtrera dubbletter
Detta är förmodligen en mindre vanlig begäran och lätt att lösa genom att användaDISTINCT
ellerGROUP BY
, men många funktioner gör detta automatiskt åt dig. Ingen verklig skillnad i prestanda i dessa fall, men det finns om det är något du glömmer att lägga till själv (tänk en stor lista, med många dubbletter, gå med i ett stort bord). Implementering:Lägg till ett alternativ för att filtrera bort dubbletter.
Här är affärsfallet.
De låter alla teoretiska, men här är affärsfallet, som jag kan försäkra er är mycket verkligt. På Wayfair har vi en betydande SQL Server-egendom, och vi har bokstavligen dussintals olika team som har skapat sina egna tabellvärderade funktioner genom åren. Vissa är bättre än andra, men de kallas alla från tusentals och åter tusentals rader kod. Vi startade nyligen ett projekt där vi försöker ersätta dem med anrop till STRING_SPLIT
, men vi stötte på blockeringsfall involverar flera av ovanstående begränsningar.
Vissa är lätta att komma runt med hjälp av en omslagsfunktion. Men enkelteckenavgränsaren begränsningen tvingade oss att utvärdera den hemska lösningen med REPLACE
, och detta visade sig eliminera prestandafördelarna vi förväntade oss, vilket fick oss att pumpa bromsarna. Och i de fallen förlorade vi ett viktigt förhandlingschip genom att driva på för uppgraderingar till kompatibilitetsnivå (alla databaser är inte på 130, strunt i 140). I dessa fall förlorar vi inte bara på STRING_SPLIT
förbättringar, men även på andra 130+ prestandaförbättringar som vi skulle uppskatta om STRING_SPLIT
hade varit tillräckligt övertygande på egen hand för att driva på uppgraderingen av kompatibiliteten.
Så jag ber om din hjälp.
Besök detta feedbackobjekt:
- STRING_SPLIT är inte komplett med funktioner
Rösta upp det! Ännu viktigare, lämna en kommentar som beskriver verkliga användningsfall du har som gör STRING_SPLIT
en smärta eller en icke-startare för dig. Enbart röster räcker inte, men med tillräckligt med påtaglig och kvalitativ feedback finns det en chans att de kan börja ta dessa luckor på allvar.
Jag känner för att stödja avgränsare med flera tecken (även om jag expanderar från [n]varchar(1)
till [n]varchar(5)
) är en diskret förbättring som kommer att avblockera många personer som delar mitt scenario. Andra förbättringar kan vara svårare att implementera, vissa kräver överbelastning och/eller språkförbättringar, så jag förväntar mig inte alla dessa korrigeringar i vNext. Men även en mindre förbättring skulle upprepa den STRING_SPLIT
var en värdefull investering, och att den inte kommer att överges (som till exempel innehöll databaser, en av de mer kända drive-by-funktionerna).
Tack för att du lyssnade!