sql >> Base de Datos >  >> RDS >> Database

Ayuda con las mejoras de STRING_SPLIT

Estamos en la mitad del ciclo entre lanzamientos, donde aún no escuchamos sobre ninguna de las características planeadas para SQL Server vNext. Este es probablemente el mejor momento para presionar a Microsoft para que realice mejoras, siempre que podamos respaldar nuestras solicitudes con casos comerciales legítimos. En SQL Server 2016, STRING_SPLIT resolvió una brecha perdida durante mucho tiempo en un lenguaje que, ciertamente, no estaba destinado al procesamiento complicado de cadenas. Y eso es lo que quiero mencionar hoy.

Durante años antes de SQL Server 2016 (y desde entonces), escribimos nuestras propias versiones, las mejoramos con el tiempo e incluso discutimos sobre cuál era la más rápida. Escribimos en un blog sobre cada microsegundo que podíamos ganar y yo, por mi parte, he declarado varias veces:"¡Esta es mi última publicación sobre dividir cadenas!" Sin embargo, aquí estamos.

Siempre argumentaré que los parámetros con valores de tabla son la forma correcta de separar cadenas. Pero mientras yo Creo que estos blobs de texto separados por comas nunca deben exponerse a la base de datos de esa forma, dividir cadenas sigue siendo un caso de uso frecuente:un par de publicaciones de mi blog aquí están entre las 5 principales en vistas todos los días .

Entonces, ¿por qué la gente sigue intentando dividir cadenas con funciones con valores de tabla cuando existe un reemplazo superior? Algunos, estoy seguro, porque todavía están en versiones anteriores, están atascados en un nivel de compatibilidad anterior o no pueden evitar dividir cadenas porque los TVP no son compatibles con su idioma u ORM. Por lo demás, mientras STRING_SPLIT es conveniente y eficiente, no es perfecto. Tiene restricciones que conllevan cierta fricción y que hacen que reemplazar las llamadas a funciones existentes con una llamada nativa sea engorroso o imposible.

Aquí está mi lista.

Estas limitaciones no son exhaustivas, pero he enumerado las importantes en mi orden de prioridad (y Andy Mallon también escribió sobre esto hoy):

  • Delimitador de un solo carácter
    Parece que la función se creó pensando únicamente en el caso de uso muy simple:CSV. Las personas tienen cadenas más complejas que 1,2,3 o A|B|C , y a menudo se alimentan a sus bases de datos desde sistemas fuera de su control. Como describo en esta respuesta y este consejo, hay formas de evitar esto (operaciones de reemplazo realmente ineficientes), pero son realmente desagradables y, francamente, anulan todos los beneficios de rendimiento que ofrece la implementación nativa. Además, parte de la fricción con este se reduce específicamente a:"Bueno, string_to_array de PostgreSQL maneja múltiples delimitadores de caracteres, entonces, ¿por qué SQL Server no puede? Implementación:aumente el tamaño máximo de separator .
  • Sin indicación del orden de entrada
    La salida de la función es un conjunto e, inherentemente, los conjuntos no tienen orden. Y aunque en la mayoría de los casos verá una cadena de entrada como bob,ted,frank salir en ese orden (bob ted frank ), no hay garantía (con o sin un (ORDER BY (SELECT NULL)) descuidado cortar a tajos). Muchas funciones caseras incluyen una columna de salida para indicar la posición ordinal en la cadena, lo que puede ser importante si la lista está organizada en un orden definido o si la posición ordinal exacta tiene algún significado. Implementación:agregue una opción para incluir la columna de posición ordinal en La salida.
  • El tipo de salida se basa solo en la entrada
    La columna de salida de la función se fija en varchar o nvarchar , y se determina con precisión por la longitud de toda la cadena de entrada, no por la longitud del elemento más largo. Entonces, tiene una lista de 25 letras, el tipo de salida es al menos varchar(51) . Para cadenas más largas, esto puede derivar en problemas con las concesiones de memoria, según el uso, y puede generar problemas si el consumidor confía en la salida de otro tipo de datos (por ejemplo, int , cuyas funciones a veces especifican para evitar conversiones implícitas más adelante). Como solución alternativa, los usuarios a veces crean sus propias tablas temporales o variables de tabla y vuelcan el resultado de la función allí antes de interactuar con ella, lo que puede generar problemas de rendimiento. Implementación:agregue una opción para especificar el tipo de salida de value .
  • No se pueden ignorar elementos vacíos o delimitadores finales
    Cuando tienes una cadena como a,,,b, , puede esperar que solo se emitan dos elementos, ya que los otros tres están vacíos. La mayoría de los TVF personalizados que he visto recortan los delimitadores finales o filtran las cadenas de longitud cero, pero STRING_SPLIT devuelve las 5 filas. Esto dificulta el intercambio en la función nativa porque también debe agregar una lógica de ajuste para eliminar estas entidades. Implementación:agregue una opción para ignorar los elementos vacíos.
  • No se pueden filtrar duplicados
    Esta es probablemente una solicitud menos común y fácil de resolver usando DISTINCT o GROUP BY , pero muchas funciones lo hacen automáticamente por usted. No hay una diferencia real en el rendimiento en estos casos, pero hay algo que olvidas agregar tú mismo (piensa en una lista grande, con muchos duplicados, uniéndose a una tabla grande).

    Implementación:Agregue una opción para filtrar duplicados.

Este es el caso de negocio.

Todo eso suena teórico, pero aquí está el caso de negocios, que les puedo asegurar que es muy real. En Wayfair, tenemos una propiedad sustancial de SQL Server y tenemos literalmente docenas de equipos diferentes que han creado sus propias funciones con valores de tabla a lo largo de los años. Algunos son mejores que otros, pero todos se llaman desde miles y miles de líneas de código. Recientemente comenzamos un proyecto en el que intentamos reemplazarlos con llamadas a STRING_SPLIT , pero nos encontramos con casos de bloqueo involucrando varias de las limitaciones anteriores.

Algunos son fáciles de solucionar, utilizando una función de contenedor. Pero el delimitador de un solo carácter La limitación nos obligó a evaluar la horrible solución usando REPLACE , y esto resultó eliminar el beneficio de rendimiento que esperábamos, obligándonos a pisar los frenos. Y en esos casos, perdimos una moneda de cambio clave al impulsar actualizaciones al nivel de compatibilidad (no todas las bases de datos están en 130, no importa 140). En esos casos, estamos perdiendo no solo en STRING_SPLIT mejoras, sino también otras más de 130 mejoras de rendimiento que disfrutaríamos si STRING_SPLIT había sido lo suficientemente convincente por sí solo como para impulsar la actualización del nivel de compatibilidad.

Entonces, estoy pidiendo su ayuda.

Visite este elemento de comentarios:

  • STRING_SPLIT no es una función completa

¡Vota! Más importante aún, deja un comentario describiendo casos de uso reales que tienes que hacen STRING_SPLIT un dolor o un no arranque para usted. Los votos por sí solos no son suficientes pero, con suficientes comentarios tangibles y cualitativos, existe la posibilidad de que empiecen a tomarse en serio estas brechas.

Tengo ganas de admitir delimitadores de varios caracteres (incluso, digamos, expandir desde [n]varchar(1) a [n]varchar(5) ) es una mejora no intrusiva que desbloqueará a muchas personas que comparten mi escenario. Otras mejoras pueden ser más difíciles de implementar, algunas requieren sobrecargas y/o mejoras de idioma, por lo que no espero todas estas correcciones en vNext. Pero incluso una pequeña mejora reiteraría que STRING_SPLIT fue una inversión que valió la pena, y que no se va a abandonar (como, por ejemplo, bases de datos contenidas, una de las funciones más famosas).

¡Gracias por escuchar!