Database
 sql >> Base de données >  >> RDS >> Database

Aidez-nous à améliorer STRING_SPLIT

Nous sommes à mi-cycle entre les versions, où nous n'avons pas encore entendu parler des fonctionnalités prévues pour SQL Server vNext. C'est probablement le meilleur moment pour faire pression sur Microsoft pour obtenir des améliorations, tant que nous pouvons étayer nos demandes par des analyses de rentabilisation légitimes. Dans SQL Server 2016, STRING_SPLIT a résolu une lacune manquante depuis longtemps dans un langage qui, certes, n'était pas destiné au traitement de chaînes compliqué. Et c'est ce que je veux aborder aujourd'hui.

Pendant des années avant SQL Server 2016 (et pendant des années depuis), nous avons écrit nos propres versions, les avons améliorées au fil du temps et nous nous sommes même disputés pour savoir laquelle était la plus rapide. Nous avons blogué sur chaque microseconde que nous pouvions gagner et, pour ma part, j'ai déclaré à plusieurs reprises, "c'est mon dernier article sur le fractionnement des chaînes!" Pourtant nous y sommes.

Je soutiendrai toujours que les paramètres de table sont le bon moyen de séparer les chaînes. Mais pendant que je Je pense que ces blobs de texte séparés par des virgules ne devraient jamais être exposés à la base de données sous cette forme, le fractionnement des chaînes continue d'être un cas d'utilisation répandu - quelques-uns de mes articles de blog ici sont dans le top 5 des vues chaque jour .

Alors, pourquoi les gens essaient-ils toujours de diviser des chaînes avec des fonctions de table alors qu'un remplacement supérieur existe ? Certains, j'en suis sûr, parce qu'ils sont toujours sur des versions plus anciennes, bloqués dans un niveau de compatibilité plus ancien, ou ne peuvent pas du tout échapper à la division des chaînes parce que les TVP ne sont pas pris en charge par leur langue ou leur ORM. Pour le reste, tant que STRING_SPLIT est à la fois pratique et efficace, il n'est pas parfait. Il a des restrictions qui entraînent des frictions et qui rendent le remplacement des appels de fonction existants par un appel natif fastidieux ou impossible.

Voici ma liste.

Ces limitations ne sont pas exhaustives, mais j'ai répertorié les plus importantes dans mon ordre de priorité (et Andy Mallon a également blogué à ce sujet aujourd'hui) :

  • Délimiteur à un seul caractère
    Il semble que la fonction ait été créée en pensant uniquement au cas d'utilisation le plus simple :CSV. Les gens ont des chaînes plus complexes que 1,2,3 ou A|B|C , et ils alimentent souvent leurs bases de données à partir de systèmes hors de leur contrôle. Comme je le décris dans cette réponse et cette astuce, il existe des moyens de contourner ce problème (opérations de remplacement vraiment inefficaces), mais ils sont vraiment laids et, très franchement, annulent tous les avantages de performances offerts par l'implémentation native. De plus, certaines des frictions avec celui-ci se résument spécifiquement à :"Eh bien, string_to_array de PostgreSQL gère plusieurs délimiteurs de caractères, alors pourquoi SQL Server ne peut-il pas ?" .
  • Pas d'indication d'ordre d'entrée
    La sortie de la fonction est un ensemble et, par nature, les ensembles n'ont pas d'ordre. Et tandis que dans la plupart des cas, vous verrez une chaîne d'entrée comme bob,ted,frank sortir dans cet ordre (bob franc ), il n'y a aucune garantie (avec ou sans un (ORDER BY (SELECT NULL)) bâclé pirater). De nombreuses fonctions maison incluent une colonne de sortie pour indiquer la position ordinale dans la chaîne, ce qui peut être important si la liste est organisée dans un ordre défini ou si la position ordinale exacte a une certaine signification. le résultat.
  • Le type de sortie est basé uniquement sur l'entrée
    La colonne de sortie de la fonction est fixée soit à varchar ou nvarchar , et est déterminé précisément par la longueur de la chaîne d'entrée entière, et non par la longueur de l'élément le plus long. Donc, vous avez une liste de 25 lettres, le type de sortie est au moins varchar(51) . Pour les chaînes plus longues, cela peut entraîner des problèmes d'attribution de mémoire, en fonction de l'utilisation, et peut introduire des problèmes si le consommateur s'appuie sur un autre type de données en sortie (par exemple, int , que les fonctions spécifient parfois pour éviter les conversions implicites ultérieurement). Pour contourner ce problème, les utilisateurs créent parfois leurs propres tables temporaires ou variables de table et y vident la sortie de la fonction avant d'interagir avec elle, ce qui peut entraîner des problèmes de performances.Implémentation :ajoutez une option pour spécifier le type de sortie de value .
  • Impossible d'ignorer les éléments vides ou les délimiteurs de fin
    Lorsque vous avez une chaîne comme a,,,b, , vous pouvez vous attendre à ce que seuls deux éléments soient générés, puisque les trois autres sont vides. La plupart des TVF personnalisés que j'ai vus suppriment les délimiteurs de fin et/ou filtrent les chaînes de longueur nulle, mais STRING_SPLIT renvoie les 5 lignes. Cela rend difficile l'échange dans la fonction native car vous devez également ajouter une logique d'encapsulation pour éliminer ces entités.Implémentation :ajoutez une option pour ignorer les éléments vides.
  • Impossible de filtrer les doublons
    Il s'agit probablement d'une requête moins courante, et facile à résoudre en utilisant DISTINCT ou GROUPER PAR , mais de nombreuses fonctions le font automatiquement pour vous. Aucune réelle différence de performances dans ces cas, mais il y en a si c'est quelque chose que vous oubliez d'ajouter vous-même (pensez à une grande liste, avec beaucoup de doublons, se joignant à une grande table).

    Implémentation :ajoutez une option pour filtrer les doublons.

Voici l'analyse de rentabilisation.

Tout cela semble théorique, mais voici l'analyse de rentabilisation, qui, je peux vous l'assurer, est très réelle. Chez Wayfair, nous avons un parc SQL Server substantiel et nous avons littéralement des dizaines d'équipes différentes qui ont créé leurs propres fonctions de table au fil des ans. Certains sont meilleurs que d'autres, mais ils sont tous appelés à partir de milliers et de milliers de lignes de code. Nous avons récemment lancé un projet dans lequel nous essayons de les remplacer par des appels à STRING_SPLIT , mais nous avons rencontré des cas bloquants impliquant plusieurs des limitations ci-dessus.

Certains sont faciles à contourner, en utilisant une fonction wrapper. Mais le délimiteur de caractère unique limitation nous a obligés à évaluer la terrible solution de contournement en utilisant REPLACE , et cela s'est avéré éliminer l'avantage de performance que nous attendions, nous obligeant à pomper les freins. Et dans ces cas, nous avons perdu une monnaie d'échange clé en faisant pression pour des mises à niveau vers le niveau de compatibilité (toutes les bases de données ne sont pas sur 130, encore moins 140). Sur ces instances, nous perdons non seulement STRING_SPLIT améliorations, mais aussi sur plus de 130 autres améliorations de performances dont nous profiterions si STRING_SPLIT avait été suffisamment convaincant à lui seul pour pousser à la mise à niveau du niveau de compatibilité.

Donc, je demande votre aide.

Veuillez consulter cet élément de commentaires :

  • STRING_SPLIT n'est pas complet

Votez pour ! Plus important encore, laissez un commentaire décrivant des cas d'utilisation réels que vous avez qui font STRING_SPLIT une douleur ou un non-starter pour vous. Les votes seuls ne suffisent pas mais, avec suffisamment de retours tangibles et qualitatifs, il y a une chance qu'ils commencent à prendre ces lacunes au sérieux.

J'ai envie de prendre en charge les délimiteurs multi-caractères (même, disons, l'expansion de [n]varchar(1) à [n]varchar(5) ) est une amélioration non intrusive qui débloquera de nombreuses personnes qui partagent mon scénario. D'autres améliorations peuvent être plus difficiles à mettre en œuvre, certaines nécessitant des surcharges et/ou des améliorations de langage, donc je ne m'attends pas à tous ces correctifs dans vNext. Mais même une amélioration mineure répéterait que STRING_SPLIT était un investissement rentable et qu'il ne sera pas abandonné (comme, par exemple, les bases de données autonomes, l'une des fonctionnalités les plus célèbres de drive-by).

Merci pour votre écoute !