Ich bin zwar nicht der Meinung, dass BLOBs nur in einer anderen Tabelle enthalten sein sollten - sie sollten überhaupt nicht in der Datenbank enthalten sein . Speichern Sie einen Zeiger darauf, wo sich die Datei auf der Festplatte befindet, und rufen Sie ihn dann einfach aus der Datenbank ab ...
Das Hauptproblem, das sie (für mich) verursachen, ist die Indizierung. Wenn Sie XML mit Abfrageplänen verwenden, lassen Sie uns eine Tabelle erstellen, da jeder sie hat:
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)
Es ist nur 1000 Zeilen, aber überprüfen Sie die Größe ...
sp_BlitzIndex @DatabaseName = 'StackOverflow', @SchemaName = 'dbo', @TableName = 'index_test'
Es ist über 40 MB für nur 1000 Zeilen. Angenommen, Sie fügen alle 1000 Zeilen 40 MB hinzu, dann kann das ziemlich schnell ziemlich hässlich werden. Was passiert, wenn Sie eine Million Zeilen erreichen? Das sind dort nur etwa 1 TB Daten.
Alle Abfragen, die Ihren Clustered-Index verwenden müssen, müssen jetzt alle diese BLOB-Daten in die Speicheraufklärung einlesen : wenn auf die BLOB-Datenspalte verwiesen wird.
Gibt es bessere Möglichkeiten, den SQL Server-Speicher zu nutzen, als BLOBs zu speichern? Weil ich es sicher kann.
Erweitern auf nicht gruppierte Indizes:
CREATE INDEX ix_noblob ON dbo.index_test (ID)
CREATE INDEX ix_returnoftheblob ON dbo.index_test (ID) INCLUDE (query_plan)
Sie können Ihre nicht gruppierten Indizes so entwerfen, dass die BLOB-Spalte weitgehend vermieden wird, sodass bei regelmäßigen Abfragen der gruppierte Index vermieden wird. Sobald Sie diese BLOB-Spalte benötigen, benötigen Sie den gruppierten Index.
Wenn Sie es INCLUDED
einem nicht gruppierten Index als Spalte hinzufügen, um ein Schlüsselsuchszenario zu vermeiden, erhalten Sie gigantische nicht gruppierte Indizes:
Weitere Probleme, die sie verursachen:
- Wenn jemand eine
SELECT *
Abfrage ausführt, erhält er alle diese BLOB-Daten.
- Sie belegen Speicherplatz in Sicherungen und Wiederherstellungen und verlangsamen diese
- Sie werden langsamer
DBCC CHECKDB
, weil ich weiß, dass Sie nach Korruption suchen, oder?
- Und wenn Sie einen Index pflegen, verlangsamen sie dies ebenfalls.
Hoffe das hilft!
Wie groß sind diese Bilder und wie viele erwarten Sie? Obwohl ich @sp_BlitzErik größtenteils zustimme , denke ich, dass es einige Szenarien gibt, in denen dies in Ordnung ist, und daher wäre es hilfreich, ein klareres Bild davon zu haben, was hier tatsächlich angefordert wird.
Einige Optionen, um zu berücksichtigen, dass die meisten negativen Aspekte, auf die Erik hingewiesen hat, gemildert werden, sind:
Beide Optionen dienen als Mittelweg zwischen dem vollständigen Speichern von BLOBs in SQL Server oder dem vollständigen Speichern außerhalb von BLOBs (mit Ausnahme einer Zeichenfolge, die den Pfad beibehält). Sie ermöglichen es BLOBs, Teil des Datenmodells zu sein und an Transaktionen teilzunehmen, ohne Platz im Pufferpool (dh Speicher) zu verschwenden. Die BLOB-Daten sind weiterhin in den Sicherungen enthalten, wodurch sie mehr Speicherplatz beanspruchen und länger für die Sicherung und die Sicherung benötigenetwas wiederherstellen. Es fällt mir jedoch schwer, dies als echtes Negativ zu sehen, da es, wenn es Teil der App ist, irgendwie gesichert werden muss und nur eine Zeichenfolgenspalte mit dem Pfad vollständig getrennt ist und BLOBs-Dateien abrufen können gelöscht, ohne dass dies in der Datenbank angegeben ist (dh ungültige Zeiger / fehlende Dateien). Es ermöglicht auch, dass Dateien in der Datenbank "gelöscht" werden, aber immer noch im Dateisystem vorhanden sind, das eventuell bereinigt werden muss (z. B. Kopfschmerzen). Wenn die Dateien jedoch RIESIG sind, ist es möglicherweise am besten, sie mit Ausnahme der Pfadspalte vollständig außerhalb von SQL Server zu belassen.
Dies hilft bei der Frage nach innen oder außen, berührt jedoch nicht die Frage nach einer einzelnen Tabelle gegenüber der Frage nach mehreren Tabellen. Ich kann sagen, dass es über diese spezifische Frage hinaus durchaus gültige Fälle gibt, in denen Tabellen auf der Grundlage von Verwendungsmustern in Spaltengruppen aufgeteilt werden. Bei 50 oder mehr Spalten wird häufig auf einige zugegriffen, bei anderen nicht. Einige Spalten werden häufig beschrieben, während andere meistens gelesen werden. Das Aufteilen von Spalten, auf die häufig zugegriffen wird, und Spalten, auf die selten zugegriffen wird, in mehrere Tabellen mit einer 1: 1-Beziehung ist häufig von Vorteil, da der Speicherplatz im Pufferpool für Daten, die Sie wahrscheinlich nicht verwenden, verschwendet wird (ähnlich wie beim regulären Speichern großer Bilder)
VARBINARY(MAX)
Spalten ist ein Problem)? Sie erhöhen auch die Leistung der Spalten, auf die häufig zugegriffen wird, indem Sie die Zeilengröße verringern und somit mehr Zeilen auf eine Datenseite passen, wodurch die Lesevorgänge (sowohl physisch als auch logisch) effizienter werden. Natürlich führen Sie auch eine gewisse Ineffizienz ein, indem Sie die PK duplizieren müssen, und jetzt müssen Sie manchmal die beiden Tabellen verknüpfen, was auch einige Abfragen (wenn auch nur geringfügig) kompliziert.Es gibt also verschiedene Ansätze, und was am besten ist, hängt von Ihrer Umgebung und dem ab, was Sie erreichen möchten.
Nicht so einfach. Hier finden Sie einige gute Informationen: Wie groß ist der LOB-Zeiger für (MAX) -Typen wie Varchar, Varbinary usw.? , aber die Grundlagen sind:
TEXT
,NTEXT
UndIMAGE
Datentypen (Standard): 16 - Byte - PointerVARCHAR(MAX)
,NVARCHAR(MAX)
,VARBINARY(MAX)
(Standardeinstellung):quelle
Wenn die Daten aus irgendeinem Grund in SQL Server gespeichert werden müssen, kann ich mir einige Vorteile vorstellen, wenn ich sie in einer separaten Tabelle speichere. Einige überzeugen mehr als andere.
Wenn Sie die Daten in einer separaten Tabelle ablegen, können Sie sie in einer separaten Datenbank speichern. Dies kann Vorteile für die geplante Wartung haben. Beispielsweise können Sie
DBCC CHECKDB
nur auf der Datenbank ausgeführt werden, die die BLOB-Daten enthält.Wenn Sie nicht immer mehr als 8000 Bytes in das BLOB einfügen, kann es sein, dass es für einige Zeilen in Reihe gespeichert wird . Möglicherweise möchten Sie dies nicht, da dadurch Abfragen verlangsamt werden, die über den Clustered-Index auf Daten zugreifen, selbst wenn die Spalte von der Abfrage nicht benötigt wird. Durch das Einfügen der Daten in eine separate Tabelle wird dieses Risiko beseitigt.
Beim Speichern außerhalb der Zeile verwendet SQL Server einen Zeiger von bis zu 24 Byte, um auf die neue Seite zu verweisen. Dies nimmt Platz in Anspruch und begrenzt die Gesamtzahl der BLOB-Spalten, die Sie einer einzelnen Tabelle hinzufügen können. Siehe Srutzkys Antwort für weitere Details.
Ein Clustered Columnstore-Index kann nicht für eine Tabelle definiert werden, die eine BLOB-Spalte enthält. Diese Einschränkung wurde entfernt und wird in SQL Server 2017 entfernt.
Wenn Sie irgendwann entscheiden, dass die Daten aus SQL Server verschoben werden sollen, ist es möglicherweise einfacher, diese Änderung vorzunehmen, wenn sich die Daten bereits in einer separaten Tabelle befinden.
quelle