LOB_DATA, escaneos de tabla lentos y algunas preguntas de E / S


19

Tengo una tabla bastante grande con una de las columnas que son datos XML con un tamaño promedio de entrada XML de ~ 15 kilobytes. Todas las demás columnas son entradas regulares, bigints, GUID, etc. Para tener algunos números concretos, digamos que la tabla tiene un millón de filas y tiene un tamaño de ~ 15 GB.

Lo que noté es que esta tabla es realmente lenta para seleccionar datos si quiero seleccionar todas las columnas. Cuando lo hago

SELECT TOP 1000 * FROM TABLE

toma alrededor de 20-25 segundos leer los datos del disco, aunque no impongo ningún orden en el resultado. Ejecuto la consulta con el caché frío (es decir, después DBCC DROPCLEANBUFFERS). Aquí están los resultados de las estadísticas de IO:

Cuenta de escaneo 1, lecturas lógicas 364, lecturas físicas 24, lecturas de lectura anticipada 7191, lecturas lógicas lob 7924, lecturas físicas lob 1690, lecturas lob de lectura anticipada 3968.

Toma ~ 15 MB de datos. El plan de ejecución muestra la exploración de índice agrupado como era de esperar.

No hay IO en el disco además de mis consultas; También he comprobado que la fragmentación del índice agrupado es cercana al 0%. Esta es una unidad SATA de nivel de consumidor, sin embargo, todavía creo que SQL Server podría escanear la tabla más rápido que ~ 100-150 MB / min.

La presencia del campo XML hace que la mayoría de los datos de la tabla se ubiquen en las páginas LOB_DATA (de hecho, ~ 90% de las páginas de la tabla son LOB_DATA).

Creo que mi pregunta es: ¿estoy en lo cierto al pensar que las páginas LOB_DATA pueden causar escaneos lentos no solo por su tamaño, sino también porque SQL Server no puede escanear el índice agrupado de manera efectiva cuando hay muchas páginas LOB_DATA en la tabla?

Aún más ampliamente: ¿se considera razonable tener una estructura de tabla / patrón de datos de este tipo? Las recomendaciones para usar Filestream generalmente indican tamaños de campo mucho más grandes, por lo que realmente no quiero ir por esa ruta. Realmente no he encontrado ninguna buena información sobre este escenario en particular.

He estado pensando en la compresión XML, pero debe hacerse en el cliente o con SQLCLR y requeriría bastante trabajo para implementarse en el sistema.

Probé la compresión, y dado que los XML son muy redundantes, puedo (en la aplicación ac #) comprimir XML de 20KB a ~ 2.5KB y almacenarlo en una columna VARBINARIA, evitando el uso de páginas de datos LOB. Esto acelera SELECTs 20 veces en mis pruebas.


Alex: no estoy seguro si viste la discusión relacionada con mi respuesta (el enlace está en un comentario debajo de mi respuesta), pero pude acercarme a reproducir tu escenario. Completé una tabla que coincidía (tanto como tenía información) con su descripción y obtuve estadísticas de E / S que son muy similares. Excepto que las "Lecturas físicas de LOB" nunca estuvieron cerca. Entonces, me preguntaba si actualizó el XML (pero no las otras columnas) y / o tuvo mucha fragmentación física de sus archivos de datos. Todavía no me importaría obtener el DDL de su tabla y su configuración de crecimiento automático para cada archivo de datos, y ¿reduce sus archivos de datos?
Solomon Rutzky

En primer lugar, muchas gracias por la respuesta detallada, no pude participar en la discusión en ese momento debido a la falta de tiempo. Ahora que mencionó esto (no lo pensé cuando se le hizo la pregunta): el campo XML se actualiza varias veces después de que se crea, y se crea en pequeño. Por lo tanto, sospecharía que inicialmente se almacena en fila, y después de algunas actualizaciones se traslada a una estructura de página LOB, y luego obtiene algunas actualizaciones más.
Alexander Shelemin

(Continúa) Verifiqué la fragmentación física de los archivos antes de hacer la pregunta, y la herramienta integrada de Windows pensó que estaba bien, por lo que no busqué más. El crecimiento automático es predeterminado, en 1 MB, creo, y los archivos de datos no se han reducido.
Alexander Shelemin

Seleccionar top 1000 * es importante en mi caso particular. Ciertamente entiendo que se considera una mala práctica, sin embargo, algunas decisiones de diseño de aplicaciones son realmente difíciles de cambiar después de haber estado vigentes durante mucho tiempo. Select * se usa básicamente como una estrategia de replicación entre bases de datos entre diferentes componentes de nuestra aplicación. Hay ventajas, por ejemplo, podemos hacer muchas manipulaciones arbitrarias con datos / esquemas sobre la marcha, lo que sería difícil con las técnicas de replicación incorporadas, pero viene con sus problemas.
Alexander Shelemin

Alex, SELECT *no es el problema si necesitas los datos XML. Solo es un problema si no desea los datos XML, en cuyo caso, ¿por qué ralentizar la consulta para recuperar datos que no utiliza? Pregunté sobre las actualizaciones del XML preguntándome si la fragmentación en las páginas LOB no se informaba con precisión. ¿Por eso pregunté en mi respuesta cómo determinó exactamente que el índice agrupado no estaba fragmentado? ¿Puede proporcionar el comando que ejecutó? ¿Y ha realizado una RECONSTRUCCIÓN completa en el Índice agrupado? (continuación)
Solomon Rutzky

Respuestas:


11

La presencia del campo XML hace que la mayoría de los datos de la tabla se ubiquen en las páginas LOB_DATA (de hecho, ~ 90% de las páginas de la tabla son LOB_DATA).

Simplemente tener la columna XML en la tabla no tiene ese efecto. Es la presencia de datos XML lo que, bajo ciertas condiciones , hace que una parte de los datos de una fila se almacene fuera de la fila, en páginas LOB_DATA. Y aunque uno (o tal vez varios ;-) podría argumentar que duh, la XMLcolumna implica que efectivamente habrá datos XML, no está garantizado que los datos XML necesiten almacenarse fuera de la fila: a menos que la fila ya esté casi llena Además de ser datos XML, los documentos pequeños (hasta 8000 bytes) pueden encajar en fila y nunca ir a una página LOB_DATA.

¿Estoy en lo cierto al pensar que las páginas LOB_DATA pueden causar escaneos lentos no solo por su tamaño, sino también porque SQL Server no puede escanear el índice agrupado de manera efectiva cuando hay muchas páginas LOB_DATA en la tabla?

El escaneo se refiere a mirar todas las filas. Por supuesto, cuando se lee una página de datos, se leen todos los datos de la fila , incluso si seleccionó un subconjunto de las columnas. La diferencia con los datos LOB es que si no selecciona esa columna, los datos fuera de la fila no se leerán. Por lo tanto, no es realmente justo llegar a una conclusión sobre qué tan eficientemente SQL Server puede escanear este índice agrupado ya que no lo probó exactamente (o probó la mitad). Seleccionó todas las columnas, que incluye la columna XML, y como mencionó, allí es donde se encuentra la mayoría de los datos.

Entonces, ya sabemos que la SELECT TOP 1000 *prueba no fue simplemente leer una serie de páginas de datos de 8k, todo en una fila, sino saltar a otras ubicaciones por cada fila . La estructura exacta de esos datos LOB puede variar en función de su tamaño. Según la investigación que se muestra aquí ( ¿Cuál es el tamaño del puntero LOB para tipos (MAX) como Varchar, Varbinary, Etc? ), Existen dos tipos de asignaciones LOB fuera de fila:

  1. Raíz en línea: para datos entre 8001 y 40,000 (realmente 42,000) bytes, si el espacio lo permite, habrá de 1 a 5 punteros (24 - 72 bytes) EN FILA que apuntan directamente a la (s) página (s) LOB.
  2. TEXT_TREE: para datos de más de 42,000 bytes, o si los punteros de 1 a 5 no pueden caber en la fila, entonces solo habrá un puntero de 24 bytes a la página de inicio de una lista de punteros a las páginas LOB (es decir, el " página "text_tree").

Una de estas dos situaciones ocurre cada vez que recupera datos LOB que tienen más de 8000 bytes o que simplemente no encajan en la fila. Publiqué una secuencia de comandos de prueba en PasteBin.com (secuencia de comandos T-SQL para probar las asignaciones y lecturas de LOB ) que muestra los 3 tipos de asignaciones de LOB (en función del tamaño de los datos), así como el efecto que cada uno de ellos tiene en lógica y lecturas físicas En su caso, si los datos XML realmente son menos de 42,000 bytes por fila, entonces ninguno de ellos (o muy poco) debería estar en la estructura TEXT_TREE menos eficiente.

Si desea probar qué tan rápido SQL Server puede escanear ese índice agrupado, haga lo siguiente SELECT TOP 1000pero especifique una o más columnas sin incluir esa columna XML. ¿Cómo afecta eso a sus resultados? Debería ser bastante más rápido.

¿Se considera razonable tener una estructura de tabla / patrón de datos de este tipo?

Dado que tenemos una descripción incompleta de la estructura real de la tabla y el patrón de datos, cualquier respuesta puede no ser óptima dependiendo de cuáles son esos detalles faltantes. Con eso en mente, diría que no hay nada obviamente irrazonable sobre la estructura de su tabla o patrón de datos.

Puedo (en la aplicación ac #) comprimir XML de 20KB a ~ 2.5KB y almacenarlo en una columna VARBINARIA, evitando el uso de páginas de datos LOB. Esto acelera SELECTs 20 veces en mis pruebas.

Eso hizo que la selección de todas las columnas, o incluso solo los datos XML (ahora en VARBINARY), sea más rápido, pero en realidad perjudica las consultas que no seleccionan los datos "XML". Suponiendo que tiene aproximadamente 50 bytes en las otras columnas y tiene un FILLFACTORde 100, entonces:

  • Sin compresión: 15k de XMLdatos deben requerir 2 páginas LOB_DATA, que luego requieren 2 punteros para la raíz en línea. El primer puntero tiene 24 bytes y el segundo 12, para un total de 36 bytes almacenados en fila para los datos XML. El tamaño total de la fila es de 86 bytes, y puede caber aproximadamente 93 de esas filas en una página de datos de 8060 bytes. Por lo tanto, 1 millón de filas requiere 10,753 páginas de datos.

  • Compresión personalizada: 2.5k de VARBINARY datos encajarán en fila. El tamaño total de la fila es 2610 (2.5 * 1024 = 2560) bytes, y solo puede ajustar 3 de esas filas en una página de datos de 8060 bytes. Por lo tanto, 1 millón de filas requiere 333,334 páginas de datos.

Ergo, la implementación de resultados de compresión personalizados en un aumento de 30 veces en las páginas de datos para el índice agrupado. Es decir, todas las consultas que usan un escaneo de índice agrupado ahora tienen aproximadamente 322,500 más páginas de datos para leer. Consulte la sección detallada a continuación para conocer las ramificaciones adicionales de hacer este tipo de compresión.

Yo advertiría contra cualquier refactorización basada en el rendimiento de SELECT TOP 1000 * . No es probable que se trate de una consulta que la aplicación incluso emitirá, y no debe usarse como la única base para optimizaciones potencialmente innecesarias.

Para obtener información más detallada y más pruebas para probar, consulte la sección a continuación.


No se puede dar una respuesta definitiva a esta pregunta, pero al menos podemos avanzar y sugerir investigaciones adicionales para ayudarnos a acercarnos a resolver el problema exacto (idealmente basado en evidencia).

Lo que sabemos:

  1. La tabla tiene aproximadamente 1 millón de filas
  2. El tamaño de la mesa es de aproximadamente 15 GB
  3. Tabla contiene una XMLcolumna y varios otros tipos de columnas: INT, BIGINT, UNIQUEIDENTIFIER, "etc."
  4. XMLel "tamaño" de la columna es, en promedio, aproximadamente 15k
  5. Después de la ejecución DBCC DROPCLEANBUFFERS, la siguiente consulta tarda entre 20 y 25 segundos en completarse:SELECT TOP 1000 * FROM TABLE
  6. El índice agrupado se está escaneando
  7. La fragmentación en el índice agrupado está cerca del 0%

Lo que creemos que sabemos:

  1. Ninguna otra actividad de disco fuera de estas consultas. ¿Estás seguro? Incluso si no hay otras consultas de los usuarios, ¿hay operaciones en segundo plano? ¿Hay procesos externos a SQL Server que se ejecutan en la misma máquina que podrían estar ocupando parte del IO? Es posible que no exista, pero no está claro según la información proporcionada.
  2. Se devuelven 15 MB de datos XML. ¿En qué se basa este número? ¿Una estimación derivada de las 1000 filas por el promedio de 15k de datos XML por fila? ¿O una agregación programática de lo que se recibió para esa consulta? Si se trata solo de una estimación, no confiaría en ella, ya que la distribución de los datos XML podría no ser incluso de la manera que implica un promedio simple.
  3. La compresión XML podría ayudar. ¿Cómo exactamente harías la compresión en .NET? ¿A través de las clases GZipStream o DeflateStream ? Esta no es una opción de costo cero. Sin duda, comprimirá algunos de los datos en un gran porcentaje, pero también requerirá más CPU, ya que necesitará un proceso adicional para comprimir / descomprimir los datos cada vez. Este plan también eliminaría por completo su capacidad para:

    • consulta de los datos XML a través de los .nodes, .value, .query, y .modifyfunciones XML.
    • indexar los datos XML.

      Tenga en cuenta (ya que mencionó que XML es "altamente redundante") que elXML tipo de datos ya está optimizado, ya que almacena los nombres de elementos y atributos en un diccionario, asignando una ID de índice entero a cada elemento y luego usando esa ID entera en todo el documento (por lo tanto, no repite el nombre completo por cada uso, ni lo repite nuevamente como una etiqueta de cierre para los elementos). Los datos reales también tienen espacios en blanco extraños eliminados. Es por eso que los documentos XML extraídos no conservan su estructura original y por qué los elementos vacíos se extraen como <element />si fueran como<element></element>. Por lo tanto, cualquier ganancia de la compresión a través de GZip (o cualquier otra cosa) solo se encontrará comprimiendo los valores del elemento y / o atributo, que es un área de superficie mucho más pequeña que podría mejorarse de lo que la mayoría esperaría, y lo más probable es que no valga la pena perder capacidades como se señaló directamente arriba.

      También tenga en cuenta que comprimir los datos XML y almacenar el VARBINARY(MAX)resultado no eliminará el acceso LOB, solo lo reducirá. Dependiendo del tamaño del resto de los datos en la fila, el valor comprimido podría encajar en la fila o aún podría requerir páginas LOB.

Esa información, si bien es útil, no es suficiente. Hay muchos factores que influyen en el rendimiento de las consultas, por lo que necesitamos una imagen mucho más detallada de lo que está sucediendo.

Lo que no sabemos, pero necesitamos:

  1. ¿Por qué el desempeño de la SELECT *materia? ¿Es este un patrón que usas en el código? Si es así, ¿por qué?
  2. ¿Cuál es el rendimiento de seleccionar solo la columna XML? ¿Cuáles son las estadísticas y el tiempo si solo haces SELECT TOP 1000 XmlColumn FROM TABLE;:?
  3. La cantidad de 20 a 25 segundos que lleva devolver estas 1000 filas está relacionada con factores de red (obtener los datos a través del cable), y cuánto está relacionado con factores del cliente (lo que representa aproximadamente 15 MB más el resto de ¿Datos XML en la cuadrícula en SSMS, o posiblemente guardarlos en el disco)?

    A veces, se pueden descomponer estos dos aspectos de la operación simplemente no devolviendo los datos. Ahora, uno podría pensar seleccionar en una tabla temporal o variable de tabla, pero esto solo introduciría algunas nuevas variables (es decir, E / S de disco para tempdb, escritura del registro de transacciones, posible crecimiento automático de datos tempdb y / o archivo de registro). espacio en la agrupación de almacenamiento intermedio, etc.). Todos esos factores nuevos pueden aumentar el tiempo de consulta. En cambio, normalmente almaceno las columnas en variables (del tipo de datos apropiado; no SQL_VARIANT) que se sobrescriben con cada nueva fila (es decir SELECT @Column1 = tab.Column1,...).

    SIN EMBARGO , como lo señaló @PaulWhite en este DBA. Preguntas y respuestas de StackExchange, las lecturas lógicas son diferentes al acceder a los mismos datos de LOB , con mi propia investigación adicional publicada en PasteBin ( secuencia de comandos T-SQL para probar varios escenarios para lecturas de LOB ) , LOB no se accede consistentemente entre SELECT, SELECT INTO, SELECT @XmlVariable = XmlColumn, SELECT @XmlVariable = XmlColumn.query(N'/'), y SELECT @NVarCharVariable = CONVERT(NVARCHAR(MAX), XmlColumn). Entonces, nuestras opciones son un poco más limitadas aquí, pero esto es lo que se puede hacer:

    1. Descarte problemas de red ejecutando la consulta en el servidor que ejecuta SQL Server, ya sea en SSMS o SQLCMD.EXE.
    2. Descarte los problemas del cliente en SSMS yendo a Opciones de consulta -> Resultados -> Cuadrícula y marcando la opción "Descartar resultados después de la ejecución". Tenga en cuenta que esta opción evitará TODAS las salidas, incluidos los mensajes, pero aún puede ser útil para descartar el tiempo que le toma al SSMS asignar la memoria por cada fila y luego dibujarla en la cuadrícula.
      Como alternativa, puede ejecutar la consulta a través de sqlcmd.exe y dirigir la salida para ir a ninguna parte a través de: -o NUL:.
  4. ¿Hay un tipo de espera asociado con esta consulta? En caso afirmativo, ¿cuál es ese tipo de espera?
  5. ¿Cuál es el tamaño de datos real para las XMLcolumnas que se devuelven ? El tamaño promedio de esa columna en toda la tabla realmente no importa si las filas "TOP 1000" contienen una porción desproporcionadamente grande de los XMLdatos totales . Si desea saber acerca de las 1000 filas principales, mire esas filas. Por favor ejecute lo siguiente:

    SELECT TOP 1000 tab.*,
           SUM(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [TotalXmlKBytes],
           AVG(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [AverageXmlKBytes]
           STDEV(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [StandardDeviationForXmlKBytes]
    FROM   SchemaName.TableName tab;
  6. El esquema exacto de la tabla. Proporcione la declaración completa CREATE TABLE , incluidos todos los índices.
  7. ¿Plan de consulta? ¿Es algo que puedes publicar? Esa información probablemente no cambiará nada, pero es mejor saber que no lo hará que adivinar que no lo hará y estar equivocado ;-)
  8. ¿Hay fragmentación física / externa en el archivo de datos? Si bien esto podría no ser un factor importante aquí, ya que está utilizando "SATA de nivel de consumidor" y no SSD o incluso SATA súper caro, el efecto de los sectores subóptimamente ordenados será más notable, especialmente a medida que el número de esos sectores eso necesita ser leído aumenta.
  9. ¿Cuáles son los resultados exactos de la siguiente consulta?

    SELECT * FROM sys.dm_db_index_physical_stats(DB_ID(),
                              OBJECT_ID(N'dbo.SchemaName.TableName'), 1, 0, N'LIMITED');

ACTUALIZAR

Se me ocurrió que debería intentar reproducir este escenario para ver si experimento un comportamiento similar. Entonces, creé una tabla con varias columnas (similar a la descripción vaga en la Pregunta), y luego la llené con 1 millón de filas, y la columna XML tiene aproximadamente 15k de datos por fila (vea el código a continuación).

Lo que descubrí es que se SELECT TOP 1000 * FROM TABLEcompleta en 8 segundos la primera vez, y de 2 a 4 segundos cada vez (sí, se ejecuta DBCC DROPCLEANBUFFERSantes de cada ejecución de la SELECT *consulta). Y mi computadora portátil de varios años no es rápida: SQL Server 2012 SP2 Developer Edition, 64 bits, 6 GB de RAM, doble 2.5 Ghz Core i5 y una unidad SATA de 5400 RPM. También estoy ejecutando SSMS 2014, SQL Server Express 2014, Chrome y varias otras cosas.

En función del tiempo de respuesta de mi sistema, repetiré que necesitamos más información (es decir, detalles sobre la tabla y los datos, los resultados de las pruebas sugeridas, etc.) para ayudar a reducir la causa del tiempo de respuesta de 20 a 25 segundos que estas viendo

SET ANSI_NULLS, NOCOUNT ON;
GO

IF (OBJECT_ID(N'dbo.XmlReadTest') IS NOT NULL)
BEGIN
    PRINT N'Dropping table...';
    DROP TABLE dbo.XmlReadTest;
END;

PRINT N'Creating table...';
CREATE TABLE dbo.XmlReadTest 
(
    ID INT NOT NULL IDENTITY(1, 1),
    Col2 BIGINT,
    Col3 UNIQUEIDENTIFIER,
    Col4 DATETIME,
    Col5 XML,
    CONSTRAINT [PK_XmlReadTest] PRIMARY KEY CLUSTERED ([ID])
);
GO

DECLARE @MaxSets INT = 1000,
        @CurrentSet INT = 1;

WHILE (@CurrentSet <= @MaxSets)
BEGIN
    RAISERROR(N'Populating data (1000 sets of 1000 rows); Set # %d ...',
              10, 1, @CurrentSet) WITH NOWAIT;
    INSERT INTO dbo.XmlReadTest (Col2, Col3, Col4, Col5)
        SELECT  TOP 1000
                CONVERT(BIGINT, CRYPT_GEN_RANDOM(8)),
                NEWID(),
                GETDATE(),
                N'<test>'
                  + REPLICATE(CONVERT(NVARCHAR(MAX), CRYPT_GEN_RANDOM(1), 2), 3750)
                  + N'</test>'
        FROM        [master].[sys].all_columns sac1;

    IF ((@CurrentSet % 100) = 0)
    BEGIN
        RAISERROR(N'Executing CHECKPOINT ...', 10, 1) WITH NOWAIT;
        CHECKPOINT;
    END;

    SET @CurrentSet += 1;
END;

--

SELECT COUNT(*) FROM dbo.XmlReadTest; -- Verify that we have 1 million rows

-- O.P. states that the "clustered index fragmentation is close to 0%"
ALTER INDEX [PK_XmlReadTest] ON dbo.XmlReadTest REBUILD WITH (FILLFACTOR = 90);
CHECKPOINT;

--

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SET STATISTICS IO, TIME ON;
SELECT TOP 1000 * FROM dbo.XmlReadTest;
SET STATISTICS IO, TIME OFF;

/*
Scan count 1, logical reads 21,       physical reads 1,     read-ahead reads 4436,
              lob logical reads 5676, lob physical reads 1, lob read-ahead reads 3967.

 SQL Server Execution Times:
   CPU time = 171 ms,  elapsed time = 8329 ms.
*/

Y, debido a que queremos factorizar el tiempo necesario para leer las páginas que no son LOB, ejecuté la siguiente consulta para seleccionar todas menos la columna XML (una de las pruebas que sugerí anteriormente). Esto regresa en 1,5 segundos de manera bastante consistente.

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SET STATISTICS IO, TIME ON;
SELECT TOP 1000 ID, Col2, Col3, Col4 FROM dbo.XmlReadTest;
SET STATISTICS IO, TIME OFF;

/*
Scan count 1, logical reads 21,    physical reads 1,     read-ahead reads 4436,
              lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1666 ms.
*/

Conclusión (por el momento) En
base a mi intento de recrear su escenario, no creo que podamos señalar ni la unidad SATA ni la E / S no secuencial como la causa principal de los 20-25 segundos, especialmente porque todavía No sé qué tan rápido vuelve la consulta cuando no se incluye la columna XML. Y no pude reproducir la gran cantidad de lecturas lógicas (no LOB) que está mostrando, pero tengo la sensación de que necesito agregar más datos a cada fila a la luz de eso y la declaración de:

~ 90% de las páginas de la tabla son LOB_DATA

Mi tabla tiene 1 millón de filas, cada una con poco más de 15k de datos XML, y sys.dm_db_index_physical_statsmuestra que hay 2 millones de páginas LOB_DATA. El 10% restante sería 222k páginas de datos IN_ROW, sin embargo, solo tengo 11,630 de ellas. Entonces, una vez más, necesitamos más información sobre el esquema real de la tabla y los datos reales.



10

¿Estoy en lo cierto al pensar que las páginas LOB_DATA pueden causar escaneos lentos no solo por su tamaño, sino también porque SQL Server no puede escanear el índice agrupado de manera efectiva

Sí, leer datos LOB no almacenados en fila conduce a E / S aleatorias en lugar de E / S secuenciales. La métrica de rendimiento del disco para usar aquí para comprender por qué es rápida o lenta es Random Read IOPS.

Los datos LOB se almacenan en una estructura de árbol donde la página de datos en el índice agrupado apunta a una página de datos LOB con una estructura raíz LOB que a su vez apunta a los datos LOB reales. Al atravesar los nodos raíz en el índice agrupado, SQL Server solo puede obtener los datos en fila mediante lecturas secuenciales. Para obtener los datos LOB, SQL Server tiene que ir a otro lugar en el disco.

Supongo que si cambiaste a un disco SSD no sufrirías tanto de esto, ya que los IOPS aleatorios para un SSD son mucho más altos que para un disco giratorio.

¿Se considera razonable tener una estructura de tabla / patrón de datos de este tipo?

Si podria ser. Depende de lo que esta mesa esté haciendo por ti.

Por lo general, los problemas de rendimiento con XML en SQL Server ocurren cuando desea usar T-SQL para consultar el XML y aún más cuando desea usar valores del XML en un predicado en una cláusula where o join. Si ese es el caso, podría echar un vistazo a la promoción de la propiedad o los índices selectivos de XML o un rediseño de las estructuras de su tabla triturando el XML en las tablas.

Probé la compresión

Lo hice una vez en un producto hace un poco más de 10 años y desde entonces me he arrepentido. Realmente extrañé no poder trabajar con los datos usando T-SQL, por lo que no se lo recomendaría a nadie si se puede evitar.


Muchas gracias por la respuesta. Con respecto a la compresión: no estoy seguro de si una estricta recomendación no está justificada, ya que la necesidad de consultar realmente esos datos de T-SQL obviamente depende de la naturaleza de los datos almacenados. En mi caso, decidí ir con compresión por ahora.
Alexander Shelemin
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.