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,3lubA|B|Ci 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_arrayPostgreSQL obsługuje wiele ograniczników znaków, więc dlaczego nie może SQL Server?"Implementacja:Zwiększ maksymalny rozmiarseparator. - 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 jakbob,ted,frankwychodzą w tej kolejności (bobtedfrank), 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 navarcharlubnvarchari 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 najmniejvarchar(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ściowychvalue. - Nie można zignorować pustych elementów lub końcowych ograniczników
Gdy masz ciąg, taki jaka,,,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, aleSTRING_SPLITzwraca 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ąDISTINCTlubGROUP 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!