¿Hay alguna manera de evitar que las UDF escalares en columnas calculadas inhiban el paralelismo?


29

Mucho se ha escrito sobre los peligros de las UDF escalares en SQL Server. Una búsqueda casual arrojará montones de resultados.

Sin embargo, hay algunos lugares donde un UDF escalar es la única opción.

Como ejemplo: cuando se trata de XML: XQuery no se puede usar como una definición de columna calculada. Una opción documentada por Microsoft es usar un UDF escalar para encapsular su XQuery en un UDF escalar y luego usarlo en una columna calculada.

Esto tiene varios efectos y algunas soluciones.

  • Se ejecuta fila por fila cuando se consulta la tabla
  • Obliga a todas las consultas de la tabla a ejecutarse en serie.

Puede sortear la ejecución fila por fila vinculando esquemáticamente la función y persistiendo la columna calculada o indizándola. Ninguno de esos métodos puede evitar la serialización forzada de consultas que llegan a la tabla, incluso cuando no se hace referencia al UDF escalar.

¿Hay alguna forma conocida de hacer eso?

Respuestas:


31

Si si usted:

  • están ejecutando SQL Server 2014 o posterior; y
  • son capaces de ejecutar la consulta con el marcador de rastreo 176 activo; y
  • la columna calculada es PERSISTED

Específicamente, se requieren al menos las siguientes versiones :

  • Actualización acumulativa 2 para SQL Server 2016 SP1
  • Actualización acumulativa 4 para SQL Server 2016 RTM
  • Actualización acumulativa 6 para SQL Server 2014 SP2

PERO para evitar un error (referencia para 2014 y para 2016 y 2017 ) introducido en esas correcciones, aplique en su lugar:

La marca de seguimiento es efectiva como una –Topción de inicio , tanto en el ámbito global como en el de sesión DBCC TRACEON, y por consulta con OPTION (QUERYTRACEON)una guía de plan.

La marca de seguimiento 176 evita la expansión persistente de la columna calculada.

La carga inicial de metadatos realizada al compilar una consulta trae todas las columnas, no solo aquellas directamente referenciadas. Esto hace que todas las definiciones de columnas calculadas estén disponibles para la coincidencia, lo que generalmente es algo bueno.

Como un efecto secundario desafortunado, si una de las columnas cargadas (calculadas) usa una función escalar definida por el usuario, su presencia deshabilita el paralelismo para toda la consulta, incluso cuando la columna calculada no se usa realmente .

La marca de seguimiento 176 ayuda con esto, si la columna persiste, al no cargar la definición (ya que se omite la expansión). De esta manera, una función escalar definida por el usuario nunca está presente en el árbol de consulta de compilación, por lo que el paralelismo no está deshabilitado.

El principal inconveniente del indicador de traza 176 (aparte de estar solo ligeramente documentado) es que también evita que la expresión de consulta coincida con columnas calculadas persistentes: si la consulta contiene una expresión que coincide con una columna calculada persistente, el indicador de seguimiento 176 evitará que la expresión sea reemplazada por Una referencia a la columna calculada.

Para obtener más detalles, consulte mi artículo de SQLPerformance.com, Columnas calculadas correctamente persistentes .

Dado que la pregunta menciona XML, como una alternativa a la promoción de valores utilizando una columna calculada y una función escalar, también puede considerar el uso de un índice selectivo de XML, como lo escribió en los índices selectivos de XML: no está nada mal .


10

Además del excelente # 1 de @ Paul , en realidad hay un # 2 que:

  • funciona desde SQL Server 2005,
  • no requiere establecer una marca de seguimiento,
  • no no requiere que la columna calculada sea PERSISTED, y
  • (debido a que no requiere el indicador de traza 176), no impide que la expresión de consulta coincida con columnas calculadas persistentes

Los únicos inconvenientes (por lo que puedo decir) son:

  • no funciona en Azure SQL Database (al menos todavía no, aunque sí funciona en Amazon RDS SQL Server y SQL Server en Linux), y
  • está un poco fuera de la zona de confort de muchos DBA

Y esta opción es: SQLCLR

Está bien. Un aspecto fresco de SQLCLR escalar UDF es que, si ellos no hacen ningún acceso a los datos (ni el usuario ni el sistema), entonces ellos no prohíben el paralelismo. Y eso no es solo teoría o marketing. Si bien no tengo tiempo (en este momento) para hacer la redacción detallada, lo he probado y comprobado.

Utilicé la configuración inicial de la siguiente publicación de blog (espero que el OP no considere que esta sea una fuente poco confiable 🙃):

Jeans de mala idea: múltiples pistas de índice

Y realizó las siguientes pruebas:

  1. Ejecutó la consulta inicial como es ral Paralelismo (como se esperaba)
  2. Se agregó una columna computada no persistente definida como ([c2] * [c3])ral Paralelismo (como se esperaba)
  3. Se eliminó esa columna calculada y se agregó una columna calculada no persistente que hacía referencia a un UDF escalar T-SQL (creado con SCHEMABINDING) definido como RETURN (@First * @Second);─⇾ NO paralelismo (como se esperaba)
  4. Se eliminó la columna calculada T-SQL UDF y se agregó una columna calculada no persistente que hacía referencia a un UDF escalar SQLCLR (probado con ambos IsDeterministic = truey= false ) definido como return SqlInt32.Multiply(First, Second);─⇾ Paralelismo (¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡! '' '' Se ha eliminado !

Entonces, si bien SQLCLR no funcionará para todos, ciertamente tiene sus ventajas para aquellas personas / situaciones / entornos que encajan bien. Y, en lo que se refiere a esta pregunta específica, el ejemplo dado sobre el uso de XQuery, funcionaría para eso (y, dependiendo de lo que se esté haciendo específicamente, incluso podría ser un poco más rápido 😎).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.