2009-02-17 6 views
5

He estado bailando sobre este tema por un tiempo pero sigue apareciendo. Tenemos un sistema y nuestra mayo de nuestras tablas comienza con una descripción que originalmente está almacenada como NVARCHAR(150) y luego obtenemos un ticket que solicita expandir el tamaño del campo a 250, luego a 1000, etc., ...¿Qué es una forma mantenible de almacenar campos de texto grandes sin sacrificar el rendimiento?

Esto el ciclo se repite en el campo de "nota" siempre y/o el campo "descripción" que agregamos a la mayoría de las tablas. Por supuesto, la preocupación para mí es el rendimiento y romper el límite de 8 k de la página. Sin embargo, mi otra preocupación es hacer que el sistema sea menos sostenible al separar estos campos de TODAS las tablas del sistema en una referencia de carga lenta.

Así que aquí estoy frente a estos mismos a 2 opciones que me han estado mirando a la cara. (otros son bienvenidos) por favor prestenme sus opiniones.

  1. Cambiar todo puede notas y/o descripciones a NVARCHAR(MAX) y asegurarnos de que excluimos estos campos en todos los listados. Básicamente, nunca haga un: SELECT * FROM [TableName] a menos que solo esté recuperando un registro.

  2. Elimine todas las notas y/o campos de descripción y reemplácelos con una referencia de clave forign a una tabla [Notes].

    CREATE TABLE [dbo].[Notes] (
    [NoteId] [int] NOT NULL,
    [NoteText] [NVARCHAR]
    (MAX) NOT NULL)

Obviamente opción de uso 1 yo preferiría porque va a cambiar tanto en nuestro sistema si vamos con 2. Sin embargo, si la opción 2 es realmente la única Una buena manera de proceder, entonces al menos puedo decir que estos cambios son necesarios y que he hecho la tarea.


ACTUALIZACIÓN: que corrió varias pruebas en una base de datos de muestra con 100.000 registros en el mismo. Lo que encuentro es que debido a que el índice de clúster escanea el IO requerido para la opción 1 es "aproximadamente" el doble que la opción 2. Si selecciono una gran cantidad de registros (1000 o más), la opción 1 es dos veces más lenta incluso si lo hago no incluir el campo de texto grande en la selección. A medida que solicito menos filas, las líneas se difuminan más. Soy una aplicación web en la que el tamaño de página de 50 es la norma, por lo que la opción 1 funcionará, pero convertiré todas las instancias en la opción 2 en el futuro cercano para la escalabilidad.

Respuesta

5

Opción 2 es mejor por varias razones:

  1. Al consultar las tablas, los grandes campos de texto llenan páginas rápidamente, obligando a la base de datos escanear más páginas para recuperar datos. Esto es especialmente gravando cuando no realmente necesita devolver los datos de texto .
  2. Como mencionó, le da una pausa limpia para cambiar los datos de una sola vez. Microsoft tiene TEXTO en desuso en SQL Server 2008, , por lo que debe seguir con VARCHAR/VARBINARY.
  3. Grupos de archivos separados. Tener todos sus datos de texto en una ubicación de almacenamiento más lenta, más barata puede ser algo que decide seguir en el futuro. Si no, no hay daño, no falta.

Mientras que la Opción 1 es más fácil por ahora, la Opción 2 le dará más flexibilidad a largo plazo. Mi sugerencia sería implementar una simple prueba de concepto con la información de "notas" separada de la tabla principal y realizar algunas de sus consultas en ambos ejemplos. Compare los planes de ejecución, las estadísticas del cliente y las lecturas de E/S lógicas (SET STATISTICS IO ON) para algunas de sus consultas con estas tablas.

Una nota rápida para aquellos que sugieren el uso de un texto/NTEXT de MSDN:

Esta característica se quitará en una versión futura de Microsoft SQL servidor. Evite utilizar esta función en el nuevo trabajo de desarrollo , y planifique modifique las aplicaciones que actualmente usan esta función. En su lugar, utilice los tipos varchar (max), nvarchar (max) y varbinary (max) . Para obtener más información, , consulte Uso de tipos de datos de gran valor.

2

me gustaría ir con la opción 2.

Puede crear una vista que une las dos tablas para hacer la transición más fácil para todos, y luego pasar por un proceso de limpieza que elimina la vista y utiliza el una sola mesa siempre que sea posible.

1

El tipo de datos TEXT/NTEXT tiene una longitud prácticamente ilimitada y ocupa casi nada en su registro.

Viene con algunas cuerdas unidas, como un comportamiento especial con las funciones de cuerda, pero para un tipo de campo secundario de "notas/descripción" esto puede ser un problema menor.

2

Desea utilizar un campo TEXTO. Los campos TEXT no se almacenan directamente en la fila; en cambio, almacena un puntero a los datos de texto. Sin embargo, esto es transparente para las consultas: si solicita un campo TEXTO, devolverá el texto real, no el puntero.

Básicamente, usar un campo TEXTO es algo entre sus dos soluciones.Mantiene las filas de la tabla mucho más pequeñas que el uso de varchar, pero aún así querrá evitar preguntarlas en sus consultas si es posible.

1

Sólo para ampliar la Opción 2

Usted podría:

Renombrar MiTabla existente para MyTable_V2

Mover la columna Notas en una tabla Notas unido (con 1: 1 de unirse ID)

Crear una VISTA llamada MyTable que se une a MyTable_V2 y tablas de notas

Cree un desencadenador INSTEAD OF en la vista MyTable que guarda la columna de Notes en la tabla de Notes (IF NULL luego elimine cualquier fila existente de Notes, si NOT NULL, luego inserte si no se encuentra; de lo contrario, actualice).Realice las acciones apropiadas en la tabla MyTable_V2

Nota: Hemos tenido problemas al hacer esto cuando hay una columna calculada en MyTable_V2 (creo que ese fue el problema, de cualquier forma hemos tocado inconvenientes al hacer esto con tablas "inusuales")

Todos los nuevos Insertar/Actualizar/Borrar código debe ser escrito para operar directamente sobre las tablas MyTable_V2 y Notas

Opcionalmente: Tener el inserto del gatillo de MiTabla registrar el hecho de que se llamaba (se puede hacer esto mínimamente ACTUALICE una fila de tabla de registro preexistente con GetDate() solo si la fecha de la fila existente es> 24 horas antes, por lo que solo se actualizará una vez al día.

Cuando ya no obtenga ningún registro, puede dejar el activador INSTEAD OF en la vista MyTable y ¡ahora es totalmente compatible con MyTable_V2!

Enorme cantidad de problemas para implementar, como suponía.

red de arrastre Alternativamente, el código para todas las referencias a MiTabla y cambiarlos a MyTable_V2, poner un punto de vista en lugar de MiTabla para SELECT solamente, y no crea el LUGAR DE gatillo.

Mi plan sería arreglar todas las instrucciones Insertar/Actualizar/Eliminar que hacen referencia a la MyTable ahora en desuso. Para mí, esto sería algo más fácil porque utilizamos nombres únicos para todas las tablas y columnas en la base de datos, y usamos los mismos nombres en todos los códigos de la aplicación, por lo que asegurarnos de haber encontrado todas las instancias mediante un simple FIND sería alto.

P.S. La opción 2 también es preferible si tiene SELECT * por ahí. Hemos tenido clientes cuyo rendimiento de aplicaciones ha disminuido vertiginosamente cuando añadieron columnas grandes de texto/blob a las tablas existentes, debido a las sentencias SELECT * "vagas". ¡Espero que ese no sea el caso en tu tienda!

Cuestiones relacionadas