Además: SQL Server 2012 muestra un rendimiento mejorado en esta área, pero no parece abordar los problemas específicos que se indican a continuación. ¡ Aparentemente, esto debería solucionarse en la próxima versión principal después de
SQL Server 2012!
Su plan muestra que las inserciones individuales están usando procedimientos parametrizados (posiblemente auto parametrizados) por lo que el tiempo de análisis / compilación para estos debe ser mínimo.
Pensé en investigar esto un poco más, así que configuré un bucle ( script ) e intenté ajustar el número de VALUES
cláusulas y registrar el tiempo de compilación.
Luego dividí el tiempo de compilación por el número de filas para obtener el tiempo de compilación promedio por cláusula. Los resultados están debajo
Hasta 250 VALUES
cláusulas presentes, el tiempo de compilación / número de cláusulas tiene una ligera tendencia al alza pero nada demasiado dramático.
Pero luego hay un cambio repentino.
Esa sección de los datos se muestra a continuación.
+------+----------------+-------------+---------------+---------------+
| Rows | CachedPlanSize | CompileTime | CompileMemory | Duration/Rows |
+------+----------------+-------------+---------------+---------------+
| 245 | 528 | 41 | 2400 | 0.167346939 |
| 246 | 528 | 40 | 2416 | 0.162601626 |
| 247 | 528 | 38 | 2416 | 0.153846154 |
| 248 | 528 | 39 | 2432 | 0.157258065 |
| 249 | 528 | 39 | 2432 | 0.156626506 |
| 250 | 528 | 40 | 2448 | 0.16 |
| 251 | 400 | 273 | 3488 | 1.087649402 |
| 252 | 400 | 274 | 3496 | 1.087301587 |
| 253 | 400 | 282 | 3520 | 1.114624506 |
| 254 | 408 | 279 | 3544 | 1.098425197 |
| 255 | 408 | 290 | 3552 | 1.137254902 |
+------+----------------+-------------+---------------+---------------+
El tamaño del plan en caché que había estado creciendo linealmente cae repentinamente, pero CompileTime aumenta 7 veces y CompileMemory se dispara. Este es el punto de corte entre el plan que es auto parametrizado (con 1000 parámetros) y uno no parametrizado. A partir de entonces, parece volverse linealmente menos eficiente (en términos de número de cláusulas de valor procesadas en un tiempo determinado).
No estoy seguro de por qué debería ser esto. Presumiblemente, cuando está compilando un plan para valores literales específicos, debe realizar alguna actividad que no se escala linealmente (como ordenar).
No parece afectar el tamaño del plan de consulta en caché cuando probé una consulta que consta completamente de filas duplicadas y tampoco afecta el orden de la salida de la tabla de las constantes (y mientras lo inserta en un montón, el tiempo dedicado a ordenar sería inútil de todos modos incluso si lo hiciera).
Además, si se agrega un índice agrupado a la tabla, el plan aún muestra un paso de clasificación explícito, por lo que no parece estar ordenando en tiempo de compilación para evitar una clasificación en tiempo de ejecución.
Traté de ver esto en un depurador, pero los símbolos públicos para mi versión de SQL Server 2008 no parecen estar disponibles, así que en su lugar tuve que buscar la UNION ALL
construcción equivalente en SQL Server 2005.
A continuación se muestra un rastro de pila típico
sqlservr.exe!FastDBCSToUnicode() + 0xac bytes
sqlservr.exe!nls_sqlhilo() + 0x35 bytes
sqlservr.exe!CXVariant::CmpCompareStr() + 0x2b bytes
sqlservr.exe!CXVariantPerformCompare<167,167>::Compare() + 0x18 bytes
sqlservr.exe!CXVariant::CmpCompare() + 0x11f67d bytes
sqlservr.exe!CConstraintItvl::PcnstrItvlUnion() + 0xe2 bytes
sqlservr.exe!CConstraintProp::PcnstrUnion() + 0x35e bytes
sqlservr.exe!CLogOp_BaseSetOp::PcnstrDerive() + 0x11a bytes
sqlservr.exe!CLogOpArg::PcnstrDeriveHandler() + 0x18f bytes
sqlservr.exe!CLogOpArg::DeriveGroupProperties() + 0xa9 bytes
sqlservr.exe!COpArg::DeriveNormalizedGroupProperties() + 0x40 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x18a bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!CQuery::PqoBuild() + 0x3cb bytes
sqlservr.exe!CStmtQuery::InitQuery() + 0x167 bytes
sqlservr.exe!CStmtDML::InitNormal() + 0xf0 bytes
sqlservr.exe!CStmtDML::Init() + 0x1b bytes
sqlservr.exe!CCompPlan::FCompileStep() + 0x176 bytes
sqlservr.exe!CSQLSource::FCompile() + 0x741 bytes
sqlservr.exe!CSQLSource::FCompWrapper() + 0x922be bytes
sqlservr.exe!CSQLSource::Transform() + 0x120431 bytes
sqlservr.exe!CSQLSource::Compile() + 0x2ff bytes
Entonces, al eliminar los nombres en el seguimiento de la pila, parece pasar mucho tiempo comparando cadenas.
Este artículo de KB indica que DeriveNormalizedGroupProperties
está asociado con lo que solía llamarse la etapa de normalización del procesamiento de consultas
Esta etapa ahora se llama enlace o algebrización y toma la salida del árbol de análisis sintáctico de la etapa anterior y genera un árbol de expresión algebrizado (árbol del procesador de consultas) para avanzar a la optimización (optimización del plan trivial en este caso) [ref] .
Probé un experimento más ( Script ) que consistía en volver a ejecutar la prueba original pero observando tres casos diferentes.
- Nombre y apellido Cadenas de 10 caracteres de longitud sin duplicados.
- Nombre y apellido Cadenas de 50 caracteres de longitud sin duplicados.
- Nombre y apellido Cadenas de 10 caracteres de longitud con todos los duplicados.
Se puede ver claramente que cuanto más largas son las cadenas, peor se ponen las cosas y que, por el contrario, cuanto más duplicados, mejores son las cosas. Como se mencionó anteriormente, los duplicados no afectan el tamaño del plan almacenado en caché, por lo que supongo que debe haber un proceso de identificación duplicada al construir el árbol de expresión algebrizado.
Editar
@Lieven muestra un lugar donde se aprovecha esta información aquí
SELECT *
FROM (VALUES ('Lieven1', 1),
('Lieven2', 2),
('Lieven3', 3))Test (name, ID)
ORDER BY name, 1/ (ID - ID)
Debido a que en el momento de la compilación puede determinar que la Name
columna no tiene duplicados, omite el orden por la 1/ (ID - ID)
expresión secundaria en el tiempo de ejecución (la ordenación en el plan solo tiene una ORDER BY
columna) y no se genera ningún error de división por cero. Si se agregan duplicados a la tabla, el operador de clasificación muestra dos orden por columnas y se genera el error esperado.