Database
 sql >> Baza danych >  >> RDS >> Database

Pomóż z ulepszeniami STRING_SPLIT

Jesteśmy w połowie cyklu między wydaniami, gdzie nie słyszymy jeszcze o żadnej z planowanych funkcji SQL Server vNext. To prawdopodobnie najlepszy czas, aby naciskać na Microsoft w celu wprowadzenia ulepszeń, o ile możemy poprzeć nasze prośby uzasadnionymi sprawami biznesowymi. W SQL Server 2016, STRING_SPLIT rozwiązał dawno brakującą lukę w języku, który wprawdzie nie był przeznaczony do skomplikowanego przetwarzania ciągów znaków. I to właśnie chcę dzisiaj poruszyć.

Na lata przed SQL Server 2016 (i przez lata później) pisaliśmy własne wersje, ulepszaliśmy je z biegiem czasu, a nawet kłóciliśmy się o to, kto jest najszybszy. Pisaliśmy na blogu o każdej mikrosekundzie, którą mogliśmy zyskać, a ja wielokrotnie powtarzałem:„to jest mój ostatni post o rozdzielaniu strun!” A jednak oto jesteśmy.

Zawsze będę twierdził, że parametry wyceniane w tabeli są właściwym sposobem na rozdzielanie ciągów. Ale gdy ja Uważam, że te oddzielone przecinkami fragmenty tekstu nigdy nie powinny być ujawniane w bazie danych w tej formie, dzielenie ciągów nadal jest powszechnym przypadkiem użycia — kilka moich postów na blogu znajduje się w pierwszej piątce wyświetleń każdego dnia .

Dlaczego więc ludzie nadal próbują dzielić ciągi za pomocą funkcji wycenianych w tabeli, gdy istnieje lepszy zamiennik? Niektóre, jestem tego pewien, ponieważ wciąż są w starszych wersjach, utknęły na starszym poziomie kompatybilności lub nie mogą w ogóle uciec od dzielenia ciągów, ponieważ TVP nie są obsługiwane przez ich język lub ORM. Co do reszty, podczas gdy STRING_SPLIT jest zarówno wygodny, jak i wydajny, nie jest doskonały. Ma ograniczenia, które powodują pewne trudności i sprawiają, że zastąpienie istniejących wywołań funkcji wywołaniem natywnym jest kłopotliwe lub niemożliwe.

Oto moja lista.

Te ograniczenia nie są wyczerpujące, ale wymieniłem te ważne w moim kolejność priorytetowa (a Andy Mallon napisał o tym dzisiaj na blogu):

  • Ogranicznik jednoznakowy
    Wygląda na to, że funkcja została utworzona tylko z myślą o prostym przypadku użycia:CSV. Ludzie mają bardziej złożone ciągi niż 1,2,3 lub A|B|C i często są wprowadzane do ich baz danych z systemów znajdujących się poza ich kontrolą. Jak opisuję w tej odpowiedzi i tej wskazówce, istnieją sposoby na obejście tego (naprawdę nieefektywne operacje zastępowania), ale są one naprawdę brzydkie i, szczerze mówiąc, cofają wszystkie korzyści wydajnościowe oferowane przez natywną implementację. Ponadto niektóre problemy z tym sprowadzają się w szczególności do:„Cóż, string_to_array PostgreSQL obsługuje wiele ograniczników znaków, więc dlaczego nie może SQL Server?"Implementacja:Zwiększ maksymalny rozmiar separator .
  • Brak wskazania kolejności wprowadzania
    Wynikiem funkcji jest zestaw i z natury zestawy nie mają kolejności. I chociaż w większości przypadków zobaczysz ciąg wejściowy, taki jak bob,ted,frank wychodzą w tej kolejności (bob ted frank ), nie ma gwarancji (z lub bez niechlujnego (ORDER BY (SELECT NULL)) włamać się). Wiele domowych funkcji zawiera kolumnę wyjściową, aby wskazać pozycję porządkową w ciągu, co może być ważne, jeśli lista jest ułożona w określonej kolejności lub dokładna pozycja porządkowa ma jakieś znaczenie.Implementacja:Dodaj opcję włączenia kolumny pozycji porządkowej w wyjście.
  • Typ wyjścia jest oparty tylko na wejściu
    Kolumna wyjściowa funkcji jest ustalona na varchar lub nvarchar i jest określana dokładnie przez długość całego ciągu wejściowego, a nie długość najdłuższego elementu. Masz więc listę 25 liter, typ danych wyjściowych to co najmniej varchar(51) . W przypadku dłuższych ciągów może to sprowadzać się do problemów z przyznawaniem pamięci, w zależności od użycia, i może powodować problemy, jeśli konsument polega na wyprowadzaniu innego typu danych (powiedzmy, int , które funkcje czasami określają, aby później uniknąć niejawnych konwersji). Jako obejście, użytkownicy czasami tworzą własne tabele tymczasowe lub zmienne tabeli i zrzucają tam dane wyjściowe funkcji przed interakcją z nią, co może prowadzić do problemów z wydajnością. Wdrożenie:Dodaj opcję, aby określić typ danych wyjściowych value .
  • Nie można zignorować pustych elementów lub końcowych ograniczników
    Gdy masz ciąg, taki jak a,,,b, , możesz oczekiwać, że zostaną wyświetlone tylko dwa elementy, ponieważ pozostałe trzy są puste. Większość niestandardowych plików TVF, które widziałem, odcina końcowe ograniczniki i/lub odfiltrowuje ciągi o zerowej długości, ale STRING_SPLIT zwraca wszystkie 5 wierszy. Utrudnia to zamianę w funkcji natywnej, ponieważ musisz również dodać logikę zawijania, aby wyeliminować te encje. Implementacja:Dodaj opcję ignorowania pustych elementów.
  • Nie można filtrować duplikatów
    Jest to prawdopodobnie mniej powszechne żądanie i łatwe do rozwiązania za pomocą DISTINCT lub GROUP BY , ale wiele funkcji robi to automatycznie. W takich przypadkach nie ma żadnej różnicy w wydajności, ale jest coś, o czym zapomniałeś dodać samodzielnie (pomyśl o dużej liście, z wieloma duplikatami, dołączanej do dużego stołu).

    Implementacja:Dodaj opcję odfiltrowywania duplikatów.

Oto uzasadnienie biznesowe.

To wszystko brzmi teoretycznie, ale oto uzasadnienie biznesowe, które zapewniam, że jest bardzo realne. W Wayfair dysponujemy pokaźnym zapleczem SQL Server i mamy dosłownie dziesiątki różnych zespołów, które przez lata tworzyły własne funkcje z wartościami tabelarycznymi. Niektóre są lepsze od innych, ale wszystkie są wywoływane z tysięcy wierszy kodu. Niedawno rozpoczęliśmy projekt, w którym próbujemy zastąpić je wywołaniami STRING_SPLIT , ale natknęliśmy się na przypadki blokowania obejmujących kilka z powyższych ograniczeń.

Niektóre są łatwe do obejścia dzięki funkcji owijarki. Ale ogranicznik pojedynczego znaku ograniczenie zmusiło nas do oceny okropnego obejścia za pomocą REPLACE , a to okazało się eliminować oczekiwane przez nas korzyści w zakresie wydajności, zmuszając nas do pompowania hamulców. I w takich przypadkach straciliśmy kluczową kartę przetargową w dążeniu do aktualizacji do poziomu kompatybilności (nie wszystkie bazy danych są na 130, nie mówiąc już o 140). W takich przypadkach tracimy nie tylko STRING_SPLIT ulepszeń, ale także innych ponad 130 ulepszeń wydajności, z których moglibyśmy korzystać, gdyby STRING_SPLIT sam w sobie był wystarczająco przekonujący, by naciskać na uaktualnienie poziomu zgodności.

Więc proszę o pomoc.

Odwiedź ten element opinii:

  • STRING_SPLIT nie jest kompletny

Zagłosuj! Co ważniejsze, zostaw komentarz opisywanie rzeczywistych przypadków użycia, które sprawiają, że STRING_SPLIT ból lub brak dla ciebie startu. Same głosy nie wystarczą, ale przy wystarczającej ilości namacalnych i jakościowych informacji zwrotnych istnieje szansa, że ​​zaczną poważnie traktować te luki.

Mam ochotę wspierać wieloznakowe ograniczniki (nawet, powiedzmy, rozwijając z [n]varchar(1) do [n]varchar(5) ) to nieinwazyjne ulepszenie, które odblokuje wiele osób, które podzielają mój scenariusz. Inne ulepszenia mogą być trudniejsze do zaimplementowania, niektóre wymagają przeciążeń i/lub ulepszeń językowych, więc nie oczekuję wszystkich tych poprawek w vNext. Ale nawet jedno drobne ulepszenie powtórzyłoby, że STRING_SPLIT była opłacalną inwestycją i nie zostanie porzucona (jak, powiedzmy, zawarte bazy danych, jedna z bardziej znanych funkcji drive-by).

Dziękujemy za wysłuchanie!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Obciążenie przyrostowe w SSIS

  2. Ograniczanie ryzyka związanego z danymi poprzez maskowanie danych

  3. Wizualizacja danych za pomocą Apache Zeppelin – samouczek

  4. Kolejny argument za procedurami składowanymi

  5. Przestarzałe funkcje do wyjęcia z przybornika – część 2