Si bien no estoy de acuerdo con que los BLOB solo estén en otra tabla, no deberían estar en la base de datos . Almacene un puntero a donde vive el archivo en el disco, y luego simplemente obtenga eso de la base de datos ...
El problema principal que causan (para mí) es con la indexación. Usando XML con planes de consulta, porque todos los tienen, hagamos una tabla:
SELECT TOP 1000
ID = IDENTITY(INT,1,1),
deq.query_plan
INTO dbo.index_test
FROM sys.dm_exec_cached_plans AS dec
CROSS APPLY sys.dm_exec_query_plan(dec.plan_handle) AS deq
ALTER TABLE dbo.index_test ADD CONSTRAINT pk_id PRIMARY KEY CLUSTERED (ID)
Son solo 1000 filas, pero verificando el tamaño ...
sp_BlitzIndex @DatabaseName = 'StackOverflow', @SchemaName = 'dbo', @TableName = 'index_test'
Tiene más de 40 MB para solo 1000 filas. Suponiendo que agregue 40 MB cada 1000 filas, eso puede volverse bastante feo rápidamente. ¿Qué sucede cuando golpeas 1 millón de filas? Eso es solo alrededor de 1 TB de datos, allí.
Cualquier consulta que necesite usar su índice agrupado ahora debe leer todos esos datos BLOB en la aclaración de la memoria : cuando se hace referencia a la columna de datos BLOB.
¿Se te ocurren mejores formas de usar la memoria de SQL Server que almacenar BLOB? Porque seguro que puedo.
Expandiéndolo a índices no agrupados:
CREATE INDEX ix_noblob ON dbo.index_test (ID)
CREATE INDEX ix_returnoftheblob ON dbo.index_test (ID) INCLUDE (query_plan)
Puede diseñar sus índices no agrupados para evitar en gran medida la columna BLOB para que las consultas regulares puedan evitar el índice agrupado, pero tan pronto como necesite esa columna BLOB, necesitará el índice agrupado.
Si lo agrega como una INCLUDED
columna a un índice no agrupado para evitar un escenario de búsqueda de claves, terminará con gigantescos índices no agrupados:
Más problemas que causan:
- Si alguien ejecuta una
SELECT *
consulta, obtiene todos esos datos BLOB.
- Ocupan espacio en las copias de seguridad y restauraciones, ralentizándolas
- Disminuyen la velocidad
DBCC CHECKDB
, porque sé que estás buscando corrupción, ¿verdad?
- Y si realiza algún mantenimiento de índice, también lo ralentizarán.
¡Espero que esto ayude!
¿Qué tan grandes son estas imágenes y cuántas espera tener? Si bien estoy mayormente de acuerdo con @sp_BlitzErik , creo que hay algunos escenarios en los que está bien hacer esto, por lo que sería útil tener una idea más clara de lo que realmente se solicita aquí.
Algunas opciones a considerar que alivian la mayoría de los aspectos negativos señalados por Erik son:
Ambas opciones están diseñadas para ser un punto intermedio entre el almacenamiento de BLOB, ya sea completamente en SQL Server o completamente fuera (excepto por un colun de cadena para retener la ruta). Permiten que los BLOB sean parte del modelo de datos y participen en las Transacciones sin desperdiciar espacio en el grupo de búferes (es decir, la memoria). Los datos BLOB todavía se incluyen en las copias de seguridad, lo que hace que ocupen más espacio y tarden más en realizar copias de seguridad yrestaurar. Sin embargo, me resulta difícil ver esto como un verdadero negativo dado que si es parte de la aplicación, entonces debe respaldarse de alguna manera, y tener solo una columna de cadena que contenga la ruta está completamente desconectada y permite que los archivos BLOB se obtengan eliminado sin indicación de eso en la base de datos (es decir, punteros inválidos / archivos faltantes). También permite que los archivos se "eliminen" dentro de la base de datos, pero que aún existan en el sistema de archivos, que eventualmente deberán limpiarse (es decir, dolor de cabeza). Pero, si los archivos son ENORMES, entonces quizás sea mejor dejar completamente fuera de SQL Server, excepto la columna de ruta.
Eso ayuda con la pregunta "dentro o fuera", pero no toca la pregunta de una sola tabla versus la de varias tablas. Puedo decir que, más allá de esta pregunta específica, existen casos válidos para dividir las tablas en grupos de columnas según los patrones de uso. A menudo, cuando uno tiene 50 o más columnas, hay algunas a las que se accede con frecuencia y otras no. Algunas columnas se escriben con frecuencia, mientras que otras se leen principalmente. Separar las columnas de acceso frecuente frente a las que se accede con poca frecuencia en varias tablas que tienen una relación 1: 1 a menudo es beneficioso porque por qué desperdiciar el espacio en el Buffer Pool para los datos que probablemente no esté utilizando (similar a por qué almacenar imágenes grandes en forma regular
VARBINARY(MAX)
columnas es un problema)? También aumenta el rendimiento de las columnas de acceso frecuente reduciendo el tamaño de la fila y, por lo tanto, ajustando más filas en una página de datos, haciendo que las lecturas (tanto físicas como lógicas) sean más eficientes. Por supuesto, también introduce cierta ineficiencia al necesitar duplicar el PK, y ahora a veces necesita unir las dos tablas, lo que también complica (aunque solo sea ligeramente) algunas consultas.Por lo tanto, hay varios enfoques que podría adoptar, y lo mejor depende de su entorno y de lo que está tratando de lograr.
No es tan simple. Puede encontrar buena información aquí. ¿Cuál es el tamaño del puntero LOB para tipos (MAX) como Varchar, Varbinary, Etc? , pero los conceptos básicos son:
TEXT
,NTEXT
yIMAGE
tipos de datos (por defecto): puntero de 16 bytesVARCHAR(MAX)
,NVARCHAR(MAX)
,VARBINARY(MAX)
(Por defecto):fuente
Si los datos deben almacenarse en SQL Server por alguna razón, puedo pensar en algunos beneficios para almacenarlos en una tabla separada. Algunos son más convincentes que otros.
Poner los datos en una tabla separada significa que puede almacenarlos en una base de datos separada. Esto puede tener ventajas para el mantenimiento programado. Por ejemplo,
DBCC CHECKDB
solo puede ejecutarse en la base de datos que contiene los datos BLOB.Si no siempre coloca más de 8000 bytes en el BLOB, es posible que se almacene en fila para algunas filas. Es posible que no desee eso porque ralentizará las consultas que acceden a los datos utilizando el índice agrupado, incluso si la consulta no necesita la columna. Poner los datos en una tabla separada elimina este riesgo.
Cuando se almacena fuera de la fila, SQL Server utiliza un puntero de hasta 24 bytes para apuntar a la nueva página. Eso ocupa espacio y limita el número total de columnas BLOB que puede agregar a una sola tabla. Vea la respuesta de srutzky para más detalles.
Un índice de almacén de columnas agrupado no se puede definir en una tabla que contiene una columna BLOB. Esta limitación eliminada se eliminará en SQL Server 2017.
Si finalmente decide que los datos se deben mover fuera de SQL Server, puede ser más fácil hacer ese cambio si los datos ya están en una tabla separada.
fuente