sql >> Database >  >> RDS >> Database

Help alstublieft met STRING_SPLIT verbeteringen

We zitten midden in de cyclus tussen releases, waar we nog niets horen over de functies die gepland zijn voor SQL Server vNext. Dit is waarschijnlijk het beste moment om Microsoft aan te dringen op verbeteringen, zolang we onze verzoeken kunnen ondersteunen met legitieme businesscases. In SQL Server 2016, STRING_SPLIT loste een lang ontbrekende leemte op in een taal die, toegegeven, niet bedoeld was voor ingewikkelde stringverwerking. En dat is wat ik vandaag ter sprake wil brengen.

Jarenlang vóór SQL Server 2016 (en jarenlang daarna) hebben we onze eigen versies geschreven, deze in de loop van de tijd verbeterd en zelfs ruzie gemaakt over wie de snelste was. We blogden over elke microseconde die we konden winnen en ik heb bijvoorbeeld meerdere keren gezegd:"dit is mijn laatste bericht over het splitsen van snaren!" Maar hier zijn we dan.

Ik zal altijd beweren dat parameters met tabelwaarde de juiste manier zijn om strings uit elkaar te halen. Maar terwijl ik geloof dat deze door komma's gescheiden klodders tekst nooit in die vorm aan de database mogen worden blootgesteld, het splitsen van strings blijft een veelvoorkomend gebruik - een paar van mijn blogposts hier staan ​​in de top 5 van weergaven elke dag .

Dus waarom proberen mensen nog steeds strings te splitsen met functies met tabelwaarde als er een superieure vervanging bestaat? Sommigen, daar ben ik zeker van, omdat ze nog steeds op oudere versies zijn, vastzitten in een ouder compatibiliteitsniveau, of helemaal niet kunnen ontsnappen aan het splitsen van strings omdat TVP's niet worden ondersteund door hun taal of ORM. Voor de rest, terwijl STRING_SPLIT is zowel handig als efficiënt, het is niet perfect. Het heeft beperkingen die enige wrijving met zich meebrengen en die het vervangen van bestaande functieaanroepen door een native aanroep omslachtig of onmogelijk maken.

Hier is mijn lijst.

Deze beperkingen zijn niet uitputtend, maar ik heb de belangrijkste opgesomd in mijn prioriteitsvolgorde (en Andy Mallon heeft hier vandaag ook over geblogd):

  • Scheidingsteken van één teken
    Het lijkt erop dat de functie is gemaakt met alleen de doodeenvoudige use-case in gedachten:CSV. Mensen hebben complexere strings dan 1,2,3 of A|B|C , en ze worden vaak naar hun databases gevoerd vanuit systemen buiten hun controle. Zoals ik in dit antwoord en deze tip beschrijf, zijn er manieren om dit te omzeilen (echt inefficiënte vervangingsbewerkingen), maar ze zijn echt lelijk en, eerlijk gezegd, maken alle prestatievoordelen van de native implementatie ongedaan. Ook komt een deel van de wrijving met deze specifiek neer op:"Nou, PostgreSQL's string_to_array verwerkt scheidingstekens voor meerdere tekens, dus waarom kan SQL Server dat niet?"Implementatie:Verhoog de maximale grootte van separator .
  • Geen indicatie van invoervolgorde
    De uitvoer van de functie is een verzameling en sets hebben inherent geen volgorde. En hoewel je in de meeste gevallen een invoertekenreeks ziet zoals bob,ted,frank kom uit in die volgorde (bob ted frank ), is er geen garantie (met of zonder een slordige (ORDER BY (SELECT NULL)) hacken). Veel zelfgebouwde functies bevatten een uitvoerkolom om de ordinale positie in de string aan te geven, wat belangrijk kan zijn als de lijst in een gedefinieerde volgorde is gerangschikt of als de exacte ordinale positie enige betekenis heeft. Implementatie:Voeg een optie toe om de ordinale positiekolom op te nemen in het resultaat.
  • Uitvoertype is alleen gebaseerd op invoer
    De uitvoerkolom van de functie is vastgezet op varchar of nvarchar , en wordt precies bepaald door de lengte van de gehele invoerreeks, niet de lengte van het langste element. Je hebt dus een lijst van 25 letters, het uitvoertype is minstens varchar(51) . Voor langere strings kan dit leiden tot problemen met geheugentoekenningen, afhankelijk van het gebruik, en kan problemen veroorzaken als de consument vertrouwt op een ander gegevenstype dat wordt uitgevoerd (zeg, int , welke functies soms specificeren om impliciete conversies later te voorkomen). Als tijdelijke oplossing maken gebruikers soms hun eigen tijdelijke tabellen of tabelvariabelen en dumpen ze de uitvoer van de functie daar voordat ze ermee werken, wat kan leiden tot prestatieproblemen. Implementatie:voeg een optie toe om het uitvoertype van value .
  • Kan lege elementen of scheidingstekens niet negeren
    Als je een string hebt zoals a,,,b, , zou je verwachten dat er maar twee elementen worden uitgevoerd, aangezien de andere drie leeg zijn. De meeste aangepaste TVF's die ik heb gezien, sneden de achterliggende scheidingstekens weg en/of filterden tekenreeksen met een lengte van nul uit, maar STRING_SPLIT geeft alle 5 rijen terug. Dit maakt het moeilijk om de native functie in te wisselen omdat je ook verpakkingslogica moet toevoegen om deze entiteiten te elimineren. Implementatie:Voeg een optie toe om lege elementen te negeren.
  • Kan geen duplicaten filteren
    Dit is waarschijnlijk een minder gebruikelijk verzoek en is eenvoudig op te lossen met DISTINCT of GROUP BY , maar veel functies doen dit automatisch voor je. In deze gevallen is er geen echt verschil in prestatie, maar als je iets vergeet zelf toe te voegen (denk aan een grote lijst, met veel duplicaten, lid worden van een grote tabel).

    Implementatie:voeg een optie toe om duplicaten uit te filteren.

Hier is de businesscase.

Die klinken allemaal theoretisch, maar hier is de businesscase, waarvan ik u kan verzekeren dat deze heel reëel is. Bij Wayfair hebben we een aanzienlijk SQL Server-domein en we hebben letterlijk tientallen verschillende teams die in de loop der jaren hun eigen tafelwaardige functies hebben gecreëerd. Sommige zijn beter dan andere, maar ze worden allemaal aangeroepen vanuit duizenden en duizenden regels code. We zijn onlangs een project gestart waarbij we ze proberen te vervangen door oproepen naar STRING_SPLIT , maar we kwamen blokkeringsgevallen tegen met een aantal van de bovenstaande beperkingen.

Sommige zijn gemakkelijk te omzeilen, met behulp van een wrapper-functie. Maar het scheidingsteken van één teken beperking dwong ons om de vreselijke oplossing te evalueren met behulp van REPLACE , en dit bleek het prestatievoordeel dat we hadden verwacht teniet te doen, waardoor we op de rem moesten trappen. En in die gevallen verloren we een belangrijke onderhandelingstroef bij het aandringen op upgrades naar compatibiliteitsniveau (niet alle databases staan ​​op 130, laat staan ​​140). In die gevallen verliezen we niet alleen STRING_SPLIT verbeteringen, maar ook over andere 130+ prestatieverbeteringen waarvan we zouden genieten als STRING_SPLIT was op zichzelf al dwingend genoeg om te streven naar de upgrade van het compat-niveau.

Dus ik vraag om je hulp.

Ga naar dit feedbackitem:

  • STRING_SPLIT is niet compleet

Stem erop! Wat nog belangrijker is, laat een reactie achter het beschrijven van echte use-cases die je hebt die STRING_SPLIT . maken een pijn of een niet-starter voor u. Stemmen alleen is niet genoeg, maar met voldoende tastbare en kwalitatieve feedback bestaat de kans dat ze deze hiaten serieus gaan nemen.

Ik heb zin om scheidingstekens met meerdere tekens te ondersteunen (zelfs, laten we zeggen, uitbreiden van [n]varchar(1) naar [n]varchar(5) ) is een onopvallende verbetering die veel mensen zal deblokkeren die mijn scenario delen. Andere verbeteringen zijn misschien moeilijker te implementeren, sommige vereisen overbelasting en/of taalverbeteringen, dus ik verwacht niet al deze oplossingen in vNext. Maar zelfs een kleine verbetering zou herhalen dat STRING_SPLIT een waardevolle investering was, en dat het niet zal worden opgegeven (zoals bijvoorbeeld ingesloten databases, een van de bekendere drive-by-functies).

Bedankt voor het luisteren!


  1. Hoe kopieer je een record in een SQL-tabel, maar verwissel je de unieke id van de nieuwe rij?

  2. Hoe records met datum van de laatste 10 dagen te vermelden?

  3. Hoe EXISTS Logical Operator te gebruiken in SQL Server - SQL Server / TSQL Tutorial Part 125

  4. Null-waarden vergelijken in MySQL