Tại sao nên lưu trữ BLOB trong các bảng SQL Server riêng biệt?


28

Câu trả lời SO được đánh giá cao này khuyên bạn nên đặt hình ảnh vào các bảng riêng biệt, ngay cả khi chỉ có mối quan hệ 1: 1 với bảng khác:

Nếu bạn quyết định đặt ảnh của mình vào bảng SQL Server, tôi thực sự khuyên bạn nên sử dụng một bảng riêng để lưu trữ những ảnh đó - không lưu trữ ảnh nhân viên trong bảng nhân viên - giữ chúng trong một bảng riêng. Theo cách đó, bảng Nhân viên có thể gọn gàng và có ý nghĩa và rất hiệu quả, giả sử bạn không cần luôn luôn chọn ảnh nhân viên, như một phần của các truy vấn của bạn.

Tại sao? Tôi có ấn tượng rằng SQL Server chỉ lưu trữ một con trỏ tới một số cấu trúc dữ liệu BLOB chuyên dụng trong bảng, vậy tại sao lại phải tự tạo một lớp gián tiếp khác? Liệu nó thực sự cải thiện hiệu suất đáng kể? Nếu đúng thì tại sao?

Câu trả lời:


15

Mặc dù tôi không đồng ý rằng các BLOB chỉ nên ở trong một bảng khác - chúng hoàn toàn không nên có trong cơ sở dữ liệu . Lưu trữ một con trỏ đến nơi tệp nằm trên đĩa, và sau đó chỉ cần lấy nó từ cơ sở dữ liệu ...

Vấn đề chính mà họ gây ra (đối với tôi) là với việc lập chỉ mục. Sử dụng XML với các gói truy vấn, vì mọi người đều hiểu, hãy tạo một bảng:

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)

Chỉ có 1000 hàng, nhưng kiểm tra kích thước ...

sp_BlitzIndex @DatabaseName = 'StackOverflow', @SchemaName = 'dbo', @TableName = 'index_test'

Đó là hơn 40 MB cho chỉ 1000 hàng. Giả sử bạn thêm 40 MB mỗi 1000 hàng, điều đó có thể trở nên khá xấu xí khá nhanh chóng. Điều gì xảy ra khi bạn đạt 1 triệu hàng? Đó chỉ là khoảng 1 TB dữ liệu.

QUẢ HẠCH

Bất kỳ truy vấn nào cần sử dụng chỉ mục được nhóm của bạn bây giờ cần phải đọc tất cả dữ liệu BLOB đó vào phần làm rõ bộ nhớ : khi cột dữ liệu BLOB được tham chiếu.

Bạn có thể nghĩ ra những cách tốt hơn để sử dụng bộ nhớ SQL Server hơn là lưu trữ BLOB không? Bởi vì tôi chắc chắn có thể.

Mở rộng nó thành các chỉ mục không bao gồm:

CREATE INDEX ix_noblob ON dbo.index_test (ID)

CREATE INDEX ix_returnoftheblob ON dbo.index_test (ID) INCLUDE (query_plan)

Bạn có thể thiết kế các chỉ mục không bao gồm của mình để tránh phần lớn cột BLOB để các truy vấn thông thường có thể tránh chỉ mục được nhóm, nhưng ngay khi bạn cần cột BLOB đó, bạn cần chỉ mục được nhóm.

Nếu bạn thêm nó dưới dạng một INCLUDEDcột vào một chỉ mục không bao gồm để tránh một kịch bản tra cứu chính, bạn sẽ kết thúc với các chỉ mục không bao gồm khổng lồ:nhập mô tả hình ảnh ở đây

Nhiều vấn đề họ gây ra:

  • Nếu bất cứ ai chạy SELECT *truy vấn, họ sẽ nhận được tất cả dữ liệu BLOB đó.
  • Chúng chiếm không gian trong các bản sao lưu và khôi phục, làm chậm chúng
  • Họ chậm lại DBCC CHECKDB, vì tôi biết bạn đang kiểm tra tham nhũng, phải không?
  • Và nếu bạn thực hiện bất kỳ chỉ số bảo trì, họ cũng làm chậm điều đó.

Hi vọng điêu nay co ich!


7
Bởi vì người dùng thường gõ CHỌN *.
Brent Ozar

Tôi nghĩ rằng những nhược điểm mà bạn đề cập là một phần lý do tại sao anh ấy khuyên bạn nên đặt các bức tranh vào một bảng riêng biệt. Nếu tôi đang chạy các báo cáo khác nhau về người dùng, tôi không cần tệp hình ảnh của họ. Nếu tôi đang tải một trang hồ sơ của một người dùng, thì đó là khi tôi tham gia vào bảng blob, phải không? Tôi có thiếu điều gì ở đây không (ví dụ như nhược điểm của bạn thực sự vẫn áp dụng ngay cả trong kịch bản này mà tôi đã mô tả?)
BVernon

11

Những hình ảnh này lớn đến mức nào, và bạn dự kiến ​​sẽ có bao nhiêu? Mặc dù tôi hầu như đồng ý với @sp_BlitzErik , tôi nghĩ rằng có một số tình huống có thể làm điều này là ổn, và vì vậy nó sẽ giúp có một bức tranh rõ ràng hơn về những gì thực sự được yêu cầu ở đây.

Một số tùy chọn để xem xét giảm bớt hầu hết các khía cạnh tiêu cực được chỉ ra bởi Erik là:

Cả hai tùy chọn này đều được thiết kế để trở thành trung gian giữa việc lưu trữ BLOB hoàn toàn trong SQL Server hoặc hoàn toàn bên ngoài (ngoại trừ chuỗi colun để giữ đường dẫn). Chúng cho phép BLOB là một phần của mô hình dữ liệu và tham gia vào Giao dịch trong khi không lãng phí không gian trong vùng đệm (tức là bộ nhớ). Dữ liệu BLOB vẫn được bao gồm trong các bản sao lưu, điều này khiến chúng chiếm nhiều dung lượng hơn và mất nhiều thời gian hơn để sao lưu để khôi phục lại. Tuy nhiên, tôi gặp khó khăn khi xem đây là một tiêu cực thực sự nếu nó là một phần của ứng dụng thì nó cần được sao lưu bằng cách nào đó và chỉ có một cột chuỗi chứa đường dẫn bị ngắt hoàn toàn và cho phép các tệp BLOB được lấy đã xóa mà không có dấu hiệu nào trong DB (tức là các con trỏ / tệp bị thiếu không hợp lệ). Nó cũng cho phép các tệp bị "xóa" trong DB nhưng vẫn tồn tại trên hệ thống tệp mà cuối cùng sẽ cần phải được dọn sạch (tức là đau đầu). Nhưng, nếu các tệp là LỚN, thì có lẽ tốt nhất là để hoàn toàn bên ngoài SQL Server ngoại trừ cột đường dẫn.

Điều đó giúp với câu hỏi "bên trong hoặc bên ngoài", nhưng không chạm vào một câu hỏi so với câu hỏi nhiều bảng. Tôi có thể nói rằng, ngoài câu hỏi cụ thể này, chắc chắn có những trường hợp hợp lệ để chia bảng thành các nhóm cột dựa trên các mẫu sử dụng. Thông thường khi một cột có từ 50 cột trở lên, có một số cột được truy cập thường xuyên và một số cột thì không. Một số cột được viết thường xuyên trong khi một số chủ yếu được đọc. Việc tách các cột truy cập thường xuyên và các cột được truy cập không thường xuyên thành nhiều bảng có mối quan hệ 1: 1 thường rất có lợi vì tại sao lại lãng phí không gian trong Vùng đệm cho dữ liệu mà bạn có thể không sử dụng (tương tự như tại sao lưu trữ hình ảnh lớn thường xuyênVARBINARY(MAX)cột là một vấn đề)? Bạn cũng tăng hiệu suất của các cột truy cập thường xuyên bằng cách giảm kích thước hàng và do đó điều chỉnh nhiều hàng hơn trên một trang dữ liệu, giúp việc đọc (cả vật lý và logic) hiệu quả hơn. Tất nhiên, bạn cũng giới thiệu một số cách không hiệu quả bằng cách cần sao chép PK và bây giờ đôi khi bạn cần tham gia hai bảng, điều này cũng làm phức tạp (dù chỉ một chút) một số truy vấn.

Vì vậy, có một số cách tiếp cận bạn có thể thực hiện, và điều gì là tốt nhất phụ thuộc vào môi trường của bạn và những gì bạn đang cố gắng thực hiện.


Tôi có ấn tượng rằng SQL Server chỉ lưu trữ một con trỏ tới một số cấu trúc dữ liệu BLOB chuyên dụng trong bảng

Không đơn giản lắm. Bạn có thể tìm thấy một số thông tin tốt ở đây, Kích thước của Con trỏ LOB cho các loại (MAX) như Varchar, Varbinary, Etc là gì? , nhưng những điều cơ bản là:

  • TEXT, NTEXTIMAGEkiểu dữ liệu (theo mặc định): con trỏ 16 byte
  • VARCHAR(MAX), NVARCHAR(MAX), VARBINARY(MAX)(Theo mặc định):
    • Nếu dữ liệu có thể vừa trong hàng, thì nó sẽ được đặt ở đó
    • Nếu dữ liệu ít hơn khoảng. 40.000 byte (bài đăng trên blog được liên kết hiển thị 40.000 là giới hạn trên nhưng thử nghiệm của tôi cho thấy giá trị cao hơn một chút) nếu có chỗ trên hàng cho cấu trúc này, thì sẽ có từ 1 đến 5 liên kết trực tiếp đến các trang LOB, bắt đầu từ 24 byte cho liên kết đầu tiên với 8000 byte đầu tiên và tăng thêm 12 byte cho mỗi liên kết bổ sung cho mỗi bộ 8000 byte bổ sung, tối đa tối đa 72 byte.
    • Nếu dữ liệu là khoảng. 40.000 byte HOẶC không đủ chỗ để lưu trữ số lượng liên kết trực tiếp thích hợp (ví dụ: chỉ còn 40 byte trên hàng và giá trị 20.000 byte cần 3 liên kết là 24 byte cho lần đầu tiên cộng thêm 12 cho hai liên kết bổ sung cho 48 byte tổng không gian trong hàng được yêu cầu), sau đó sẽ chỉ có một con trỏ 24 byte đến trang cây văn bản có chứa các liên kết đến các trang LOB).

7

Nếu dữ liệu phải được lưu trữ trong SQL Server vì bất kỳ lý do gì, tôi có thể nghĩ ra một vài lợi ích để lưu trữ nó trong một bảng riêng biệt. Một số có sức thuyết phục hơn những người khác.

  1. Đặt dữ liệu vào một bảng riêng có nghĩa là bạn có thể lưu trữ nó trong một cơ sở dữ liệu riêng. Điều này có thể có lợi thế cho bảo trì theo lịch trình. Ví dụ: bạn chỉ có thể chạy DBCC CHECKDBtrên cơ sở dữ liệu chứa dữ liệu BLOB.

  2. Nếu bạn không luôn đặt hơn 8000 byte vào BLOB thì có thể nó sẽ được lưu liên tiếp cho một số hàng. Bạn có thể không muốn điều đó bởi vì nó sẽ làm chậm các truy vấn truy cập dữ liệu bằng cách sử dụng chỉ mục được nhóm ngay cả khi cột không cần thiết bởi truy vấn. Đặt dữ liệu vào một bảng riêng biệt sẽ loại bỏ rủi ro này.

  3. Khi được lưu ngoài hàng, SQL Server sử dụng một con trỏ lên đến 24 byte để trỏ đến trang mới. Điều đó chiếm không gian và giới hạn tổng số cột BLOB bạn có thể thêm vào một bảng. Xem câu trả lời của srutzky để biết thêm chi tiết.

  4. Không thể xác định chỉ mục cửa hàng cột được phân cụm trên bảng có chứa cột BLOB. Giới hạn này đã được xóa sẽ được xóa trong SQL Server 2017.

  5. Nếu cuối cùng bạn quyết định rằng dữ liệu nên được di chuyển ra ngoài SQL Server, việc thay đổi đó có thể dễ dàng hơn nếu dữ liệu đã ở trong một bảng riêng biệt.


1
Một số điểm tốt ở đây (+1). Nhưng để rõ ràng về # 3 (re: con trỏ 24 byte cho dữ liệu ngoài hàng), điều đó không phải lúc nào cũng đúng. Tôi giải thích (ngắn gọn) ở cuối câu trả lời của tôi về cách thức kiểu dữ liệu, kích thước của giá trị và lượng không gian trống trên hàng xác định kích thước của con trỏ.
Solomon Rutzky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.