Vi er midt i cyklussen mellem udgivelser, hvor vi endnu ikke hører om nogen af de funktioner, der er planlagt til SQL Server vNext. Dette er sandsynligvis det bedste tidspunkt at presse Microsoft for forbedringer, så længe vi kan understøtte vores anmodninger med legitime forretningssager. I SQL Server 2016, STRING_SPLIT
løst et længe savnet hul i et sprog, der ganske vist ikke var beregnet til kompliceret strengbehandling. Og det er det, jeg vil tage op i dag.
I årevis før SQL Server 2016 (og i årevis siden) har vi skrevet vores egne versioner, forbedret dem over tid og endda skændtes om, hvem der var hurtigst. Vi bloggede om hvert mikrosekund, vi kunne vinde, og jeg har for det første udtalt flere gange, "dette er mit sidste indlæg om at splitte strenge!" Men her er vi.
Jeg vil altid hævde, at tabelværdiparametre er den rigtige måde at adskille strenge på. Men mens jeg mener, at disse kommaseparerede tekstklatter aldrig bør eksponeres for databasen i den form, er opdelingsstrenge fortsat et udbredt tilfælde – et par af mine blogindlæg her er i top 5 i visninger hver eneste dag .
Så hvorfor forsøger folk stadig at opdele strenge med funktioner med tabelværdi, når der findes en overlegen erstatning? Nogle er jeg sikker på, fordi de stadig er på ældre versioner, sidder fast i et ældre kompatibilitetsniveau eller slet ikke kan komme væk fra at splitte strenge, fordi TVP'er ikke understøttes af deres sprog eller ORM. For resten, mens STRING_SPLIT
er både praktisk og effektiv, den er ikke perfekt. Den har begrænsninger, der medfører en vis friktion, og som gør det enten besværligt eller umuligt at erstatte eksisterende funktionskald med et indbygget kald.
Her er min liste.
Disse begrænsninger er ikke udtømmende, men jeg har listet de vigtige i min prioriteret rækkefølge (og Andy Mallon bloggede også om dette i dag):
- Enkelttegnsadskiller
Det ser ud til, at funktionen blev oprettet med kun den simple use case i tankerne:CSV. Folk har mere komplekse strenge end1,2,3
ellerA|B|C
, og de føres ofte til deres databaser fra systemer uden for deres kontrol. Som jeg beskriver i dette svar og dette tip, er der måder at omgå dette på (virkelig ineffektive erstatningsoperationer), men de er virkelig grimme og helt ærligt fortryder alle de ydeevnefordele, som den indbyggede implementering tilbyder. Også noget af friktionen med denne kommer specifikt ned til:"Nå, PostgreSQL'sstring_to_array
håndterer flere tegnafgrænsere, så hvorfor kan SQL Server ikke?"Implementering:Forøg den maksimale størrelse påseparator
. - Ingen indikation af inputrækkefølge
Udgangen af funktionen er et sæt, og sæt har i sagens natur ingen rækkefølge. Og mens du i de fleste tilfælde vil se en inputstreng sombob,ted,frank
komme ud i den rækkefølge (bob
ted
frank
), er der ingen garanti (med eller uden en sjusket(ORDER BY (SELECT NULL))
hack). Mange hjemmebyggede funktioner inkluderer en udgangskolonne for at angive ordenspositionen i strengen, hvilket kan være vigtigt, hvis listen er arrangeret i en defineret rækkefølge eller nøjagtig ordensposition har en vis betydning.Implementering:Tilføj en mulighed for at inkludere ordenspositionskolonnen i outputtet. - Outputtype er kun baseret på input
Udgangskolonnen for funktionen er fastsat til entenvarchar
ellernvarchar
, og bestemmes præcist af længden af hele inputstrengen, ikke længden af det længste element. Så du har en liste med 25 bogstaver, outputtypen er mindstvarchar(51)
. For længere strenge kan dette sive ned til problemer med hukommelsesbevillinger, afhængigt af brug, og kan introducere problemer, hvis forbrugeren stoler på, at en anden datatype udlæses (f.eks.int
, hvilke funktioner nogle gange specificerer for at undgå implicitte konverteringer senere). Som en løsning opretter brugere nogle gange deres egne midlertidige tabeller eller tabelvariabler og dumper outputtet af funktionen der, før de interagerer med det, hvilket kan føre til ydeevneproblemer.Implementering:Tilføj en mulighed for at angive outputtypen forvalue
. - Kan ikke ignorere tomme elementer eller efterfølgende afgrænsninger
Når du har en streng soma,,,b,
, kan du forvente, at kun to elementer udlæses, da de tre andre er tomme. De fleste brugerdefinerede TVF'er, jeg har set trimme bagerste afgrænsninger af og/eller filtrere nullængde strenge fra, menSTRING_SPLIT
returnerer alle 5 rækker. Dette gør det svært at bytte i den oprindelige funktion, fordi du også skal tilføje indpakningslogik for at eliminere disse entiteter.Implementering:Tilføj en mulighed for at ignorere tomme elementer. - Kan ikke filtrere dubletter
Dette er sandsynligvis en mindre almindelig anmodning og nem at løse ved at brugeDISTINCT
ellerGROUP BY
, men mange funktioner gør dette automatisk for dig. Ingen reel forskel i ydeevne i disse tilfælde, men der er, hvis det er noget, du glemmer at tilføje selv (tænk på en stor liste, med mange dubletter, tilføj til et stort bord). Implementering:Tilføj en mulighed for at filtrere dubletter fra.
Her er business casen.
De lyder alle teoretiske, men her er business casen, som jeg kan forsikre dig om er meget reel. Hos Wayfair har vi en betydelig SQL Server-ejendom, og vi har bogstaveligt talt snesevis af forskellige teams, der har skabt deres egne tabel-vurderede funktioner gennem årene. Nogle er bedre end andre, men de kaldes alle fra tusinder og atter tusinder af kodelinjer. Vi startede for nylig et projekt, hvor vi forsøger at erstatte dem med opkald til STRING_SPLIT
, men vi løb ind i blokeringssager involverer flere af ovenstående begrænsninger.
Nogle er nemme at omgås ved hjælp af en indpakningsfunktion. Men enkelttegnsadskilleren begrænsning tvang os til at evaluere den forfærdelige løsning ved at bruge REPLACE
, og dette viste sig at eliminere den præstationsfordel, vi forventede, og fik os til at pumpe bremserne. Og i disse tilfælde mistede vi en vigtig forhandlingschip ved at presse på for opgraderinger til kompatibilitetsniveau (ikke alle databaser er på 130, pyt med 140). I disse tilfælde taber vi ikke kun på STRING_SPLIT
forbedringer, men også på andre 130+ præstationsforbedringer, vi ville nyde, hvis STRING_SPLIT
havde været overbevisende nok i sig selv til at presse på for opgraderingen af compat-niveauet.
Så jeg beder om din hjælp.
Besøg venligst dette feedbackelement:
- STRING_SPLIT er ikke funktion komplet
Stem på det! Endnu vigtigere, smid en kommentar beskriver virkelige use cases, du har, der gør STRING_SPLIT
en smerte eller en ikke-starter for dig. Stemmer alene er ikke nok, men med tilstrækkelig håndgribelig og kvalitativ feedback er der en chance for, at de kan begynde at tage disse huller alvorligt.
Jeg har lyst til at understøtte afgrænsere med flere tegn (selv f.eks. udvide fra [n]varchar(1)
til [n]varchar(5)
) er en upåtrængende forbedring, der vil fjerne blokeringen af mange mennesker, der deler mit scenarie. Andre forbedringer kan være sværere at implementere, nogle kræver overbelastning og/eller sprogforbedringer, så jeg forventer ikke alle disse rettelser i vNext. Men selv en mindre forbedring ville gentage den STRING_SPLIT
var en værdifuld investering, og at den ikke vil blive opgivet (som f.eks. indeholdte databaser, en af de mere berømte drive-by-funktioner).
Tak fordi du lyttede!