Lợi ích có thể của việc lưu trữ nhiều giá trị trong một trường của một hàng thay vì dưới dạng các hàng riêng biệt


11

Trong cuộc họp hàng tuần cuối cùng của chúng tôi, một người không có kinh nghiệm về Quản trị cơ sở dữ liệu đã đưa ra câu hỏi này:

"Sẽ có một kịch bản chỉ ra việc lưu trữ dữ liệu trong dòng (chuỗi) thay vì một vài dòng?"

Chúng ta hãy giả sử một bảng được gọi là countryStatesnơi chúng ta muốn lưu trữ các trạng thái của một quốc gia; Tôi sẽ sử dụng Hoa Kỳ cho ví dụ này và sẽ không liệt kê tất cả các Bang vì sự lười biếng.

Ở đó chúng tôi sẽ có hai cột; Một người gọi Countryvà người kia gọi States. Như đã thảo luận ở đây và được đề xuất bởi câu trả lời của @ srutzky , đây PKsẽ là mã được xác định bởi ISO 3166-1 alpha-3 .

Bảng của chúng tôi sẽ trông như thế này:

+---------+-----------------------+-------------------------------------------------------+
| Country | States                | StateName                                             |
+---------+-----------------------+-------------------------------------------------------+
| USA     | AL, CA, FL,OH, NY, WY | Alabama, California, Florida, Ohio, New York, Wyoming |
+---------+-----------------------+-------------------------------------------------------+

Khi đặt câu hỏi tương tự cho nhà phát triển bạn bè, ông nói rằng từ quan điểm kích thước lưu lượng dữ liệu, điều này có thể hữu ích, nhưng không phải nếu chúng ta cần thao tác dữ liệu này. Trong trường hợp này, sẽ phải có một trí thông minh về mã ứng dụng có thể chuyển đổi chuỗi này trong danh sách (giả sử rằng phần mềm có quyền truy cập vào bảng này cần phải tạo hộp tổ hợp).

Chúng tôi kết luận rằng mô hình này không hữu ích lắm, nhưng tôi đã nghi ngờ rằng có thể có một cách để làm cho nó hữu ích.

Điều tôi muốn hỏi là liệu có ai trong số các bạn đã nhìn thấy, nghe hoặc làm điều gì đó như thế này theo cách thực sự hiệu quả không .


Bây giờ hãy tưởng tượng bạn có một bảng thứ hai, "doanh số", có dữ liệu cho mỗi lần bán hàng xảy ra cùng với mã trạng thái trong đó việc bán hàng xảy ra. Làm thế nào bạn có thể viết một truy vấn tạo ra một báo cáo với các cột (StateName, TotalSalesAmount)? Khó khăn phải không?
zgguy

Chính xác. Tôi cũng không đồng ý với mô hình này. Chúng tôi bị kẹt tại bất kỳ thời điểm nào mà chúng tôi cần khôi phục bất kỳ loại dữ liệu nào (hoặc dữ liệu hữu ích nếu bạn muốn).
Human_AfterTất cả

Một kịch bản có thể là lưu trữ các biến. Cửa hàng a;b;c, sử dụng trước hết để phân tích chuỗi của bạn, bạn sau đó nhận được a, b, cvà mang về thực hiện làm điều gì đó với họ, có lẽ ?. Cảm thấy nó có thể phù hợp với một số nhu cầu cụ thể trong thời trang đó ... Về ý nghĩ thứ hai, không. Bạn luôn có thể lưu trữ ID, Tham gia các bảng của mình và tạo một chuỗi kết nối hơn là có thể gửi nội dung đến FE ...
Nelz

Để công bằng (với tôi, ít nhất là ;-), tôi đã đề xuất sử dụng mã quốc gia gồm 2 ký tự :-) trong câu trả lời khác đó .
Solomon Rutzky

2
Lưu ý rằng không ai có ý định lưu trữ giá trị "Alabama" trong một cột thay vì có một bảng riêng biệt với các cột STATE, N & C cho "tên bang STATE có ký tự Nth C". Bởi vì 1. chúng tôi không có ý định truy vấn về các ký tự của tên hoặc 2. chúng tôi không ngại gọi hàm NTH_CHAR (N, S) trả về "ký tự thứ N của chuỗi S" trên mỗi hàng bằng tên nếu chúng tôi làm . (Vs THAM GIA & các toán tử quan hệ khác loại bỏ một số hàng như vậy thông qua bảng phụ.) Ditto cho số nguyên và NTH_DIGIT (N, I). Nó luôn luôn là một lời kêu gọi phán xét như những gì trong một cơ sở dữ liệu cụ thể là nguyên tử tương đối.
philipxy

Câu trả lời:


13

Để bắt đầu, tiêu đề Câu hỏi hiện tại đề cập đến "lưu trữ dữ liệu dưới dạng chuỗi thay vì cột" hơi khó hiểu. Khi nói về việc lưu trữ dữ liệu dưới dạng chuỗi thay vì một thứ khác, điều đó thường đề cập đến việc tuần tự hóa mọi thứ thành định dạng chuỗi thay vì kiểu dữ liệu thích hợp / mạnh (ví dụ INThoặc DATETIME). Nhưng nếu hỏi về việc lưu trữ dữ liệu dưới dạng nhiều giá trị trong một trường trái ngược với các hàng riêng biệt thì điều đó hơi khác một chút. Và để có sự công bằng, trong khi concatenating giá trị được một cách dễ dàng nhất thực hiện với chuỗi, nó cũng có thể được thực hiện với INTBINARYloại là tốt, hoặc bằng cách bit mặt nạ hoặc tương tự đặt vị trí nhất định để có ý nghĩa khác nhau. Vì cách hiểu thứ hai là những gì thực sự được hỏi về, dựa trên văn bản của Câu hỏi, hãy giải quyết nó.

Nói một cách dễ hiểu: Không. Nếu bạn đang lưu trữ các điểm dữ liệu thực tế thì nó sẽ chỉ mang lại sự đau đớn (về mã và hiệu suất) vì đó là sự phức tạp không cần thiết. Nếu đó là một giá trị sẽ chỉ được lưu trữ dưới dạng một đơn vị, được cập nhật dưới dạng một đơn vị và không bao giờ được phân tách trong cơ sở dữ liệu, thì điều đó có thể ổn vì nó tương tự như lưu trữ hình ảnh hoặc PDF. Nếu không, bất kỳ nỗ lực để phân tích dữ liệu sẽ làm mất hiệu lực sử dụng bất kỳ chỉ số (ví dụ sử dụng LIKE '%something%', hoặc CHARINDEX, hoặc PATINDEX, hoặc SUBSTRING, vv).

Nếu bạn cần lưu trữ các giá trị riêng biệt trong một trường của một hàng thì có nhiều phương tiện phù hợp hơn để thực hiện điều đó: XML hoặc JSON. Đây là các định dạng có thể phân tích cú pháp ( XML / JSON ) và XML thậm chí có thể được lập chỉ mục . Nhưng lý tưởng là dữ liệu này sẽ được lưu trữ trong các trường được nhập đúng để nó có thể thực sự hữu ích.

Và xin đừng quên rằng mục đích của RDBMS là lưu trữ dữ liệu sao cho có thể truy xuất thao tác một cách hiệu quả nhất có thể, trong các ràng buộc được áp đặt bởi ACID -compliant. Việc truy xuất các giá trị được nối là đủ tệ do phải phân tích các giá trị trước và điều đó không thể lập chỉ mục được. Nhưng thao tác thường có nghĩa là thay thế toàn bộ blob chỉ để cập nhật một phần của nó (giả sử rằng không có mẫu nào tồn tại để sử dụng với REPLACEhàm). Kiểu dữ liệu XML ít nhất cho phép XML DML cho các cập nhật đơn giản, mặc dù chúng không nhanh bằng một bản cập nhật đơn giản của dữ liệu được mô hình đúng.

Ngoài ra, với một kịch bản như những gì được hiển thị trong Câu hỏi ở trên, bằng cách ghép tất cả các Mã trạng thái lại với nhau, bạn sẽ không thể nhập Khóa ngoài (theo một trong hai hướng) các giá trị đó.

Và nếu các yêu cầu kinh doanh thay đổi theo thời gian và bạn cần theo dõi các thuộc tính bổ sung của các mặt hàng này thì sao? Về mặt "các tiểu bang", còn về thủ đô, dân số, hoặc một thứ tự sắp xếp, hoặc bất cứ điều gì khác? Được lưu trữ đúng như các hàng bạn có thể thêm nhiều cột cho các thuộc tính bổ sung. Chắc chắn, bạn có thể có nhiều cấp dữ liệu có thể phân tích cú pháp, chẳng hạn như |StateCode,Capital,Population |StateCode,Capital,Populate|...nhưng hy vọng bất cứ ai cũng có thể thấy vấn đề tăng theo cấp số nhân ngoài tầm kiểm soát. Tất nhiên, vấn đề cụ thể này khá dễ dàng xử lý các định dạng XML và JSON và đó là giá trị của chúng như đã đề cập ở trên. Nhưng bạn vẫn sẽ cần một lý do rất chính đáng để sử dụng một trong hai phương thức này làm phương tiện mô hình hóa ban đầu vì sẽ không bao giờ hiệu quả như sử dụng các trường rời rạc trong các hàng riêng biệt.


9

Tôi thực sự đã sử dụng một cái gì đó như thế cho một mục đích rất hạn chế. Chúng tôi đã tạo một bảng tiêu đề cho các tập tin đầu ra. Chúng được xây dựng đặc biệt và chủ yếu chỉ là các tiêu đề cột nhưng không hoàn toàn. Vì vậy, dữ liệu trông giống như

OutputType   OutputHeader
PersonalData Name|Address|City|State|Zip
JobInfo      Name|JobName|JobTitle

Về cơ bản, nó trông giống như một danh sách giới hạn. Và theo một cách nào đó. Nhưng với mục đích của chúng tôi, đó là một chuỗi dài duy nhất.

Đó là mẹo ở đây. Nếu bạn không bao giờ có kế hoạch phân tích danh sách thì nên lưu danh sách đó. Tuy nhiên, nếu bạn sẽ hoặc thậm chí có thể cần phân tích danh sách thì nó đáng giá thêm không gian & thời gian để tách nó ra và lưu nó thành các hàng riêng biệt.


1

Tôi đã sử dụng nó một lần với một bảng khá nhỏ, ví dụ:

CREATE TABLE t1 (
  ID number,
  some_feature   varchar2(100),
  valid_channels  varchar2(100));

CREATE TABLE channel_def (
  channel varchar2(100));

Và sau đó lưu trữ giá trị CRM,SMS,SELF-CAREvào valid_channel.

Toàn bộ bảng có khoảng 10 hồ sơ. valid_channelchứa các giá trị thực sự phải có trong một bảng liên kết mô tả mối quan hệ nhiều-nhiều. Bảng t1sẽ không được sử dụng nhiều vì vậy chúng tôi quyết định đi theo con đường này. Một số chính trị đã tham gia vào quyết định này, mặc dù (xem bên dưới).

Nhưng nói chung tôi tránh nó, nó không phải là 3NF.

Nơi tôi làm việc hiện có hàng chục cột như vậy ở khắp nơi. Biện minh của họ là nó làm cho các truy vấn của họ dễ dàng hơn: thay vì nối ba bảng bằng bảng liên kết, họ có thể đi thẳng vào bảng định nghĩa bằng cách sử dụng LIKE. Ví dụ

SELECT * 
  FROM t1 
 INNER JOIN channel_def cd
    ON ','||t1.valid_channels||',' LIKE '%,'||cd.channel||',%';

Hor khiếp + trên Oracle nó vô hiệu hóa việc sử dụng chỉ mục vì bắt đầu '%,'.


Mà sẽ chậm hơn: LIKEhoặc tham gia đơn giản?
Human_AfterTất cả

Tốt nhất là có một tham gia trên một cột được lập chỉ mục hoặc ít nhất là có một ràng buộc tham chiếu (FK) trên đó. Ngoài ra, các phép nối thường được thực hiện trên PK của bảng khác, được lập chỉ mục theo mặc định (ít nhất là trên Oracle). Nếu bạn đang hỏi về trường hợp cụ thể trong tay (xem bên trên), kế hoạch thực hiện rất có thể sẽ nói nó giống nhau, vì đó là một cái bàn nhỏ.
Robotron

@Human_AfterTất cả LIKEsẽ chậm hơn, đặc biệt là nếu dữ liệu được mô hình hóa đúng để sử dụng TINYINTtrường PK trong channel_def. Sau đó, nó chỉ cần so sánh một byte giữa hai bảng. Ở đây, nó phải phân tích chuỗi, ký tự theo từng ký tự (ít nhất là cho đến khi điều kiện được thỏa mãn) và nó đang thực hiện tìm kiếm không phân biệt chữ hoa chữ thường (dựa trên bảng đã cho không hiển thị _BIN2đối chiếu được sử dụng). Điều này cũng không hợp lệ các chỉ mục trên SQL Server. Tôi đã giải quyết điều này trong câu trả lời của mình bằng cách nói rằng phân tích cú pháp không thể sử dụng các chỉ mục. Tôi chỉ cập nhật câu trả lời của tôi để làm cho nó rõ ràng hơn.
Solomon Rutzky

1
@Human_AfterTất cả tôi sẽ nói rằng quyết định làm người mẫu này được sinh ra do thiếu kinh nghiệm và kiến ​​thức (và đôi khi là sự lười biếng). Một THAM GIA bổ sung là tất cả những gì được lưu, nhưng điều hy sinh là khả năng Foreign Key sẽ ngăn dữ liệu hoàn toàn không có thật vào (ngay cả khi nó không khớp với LIKEđiều khoản và tạo ra kết quả kỳ lạ, nó vẫn có thể gây ra các vấn đề khác hoặc ít nhất làm cho việc gỡ lỗi khó hơn / lâu hơn). Nó cũng làm cho việc cập nhật các valid_channelslĩnh vực phức tạp hơn. Điều này không có nghĩa là điều này không hiệu quả, không lý do chính đáng để làm điều đó.
Solomon Rutzky

"thiếu kinh nghiệm" - điều tồi tệ nhất là quyết định thiết kế đặc biệt này được áp đặt bởi một nhân viên cấp cao ...
Robotron

1

Điều này đã được thực hiện ở đây trên SE. Như Marc Gravell viết :

... Sau khi suy nghĩ và cân nhắc, chúng tôi đã giải quyết một biểu diễn tự nhiên được phân định bằng đường ống (bar), với các đường ống dẫn / đuôi, do đó, .net cnet đã trở thành đơn giản là | | .net | c # |. Điều này có những đức tính:

  • rất đơn giản để phân tích
  • cập nhật hàng loạt và loại bỏ các thẻ có thể được thực hiện bằng một thay thế đơn giản (bao gồm các đường ống, để tránh thay thế các thẻ khớp giữa)
  • ...

"Định dạng mới" này là bước tiếp theo từ "định dạng cũ" khác một chút và được chọn để sử dụng tính năng Tìm kiếm toàn văn bản của SQL Server, vì vậy một số lợi ích không liên quan nếu bạn thực hiện từ đầu.

Họ có lẽ đã không hoàn toàn bình thường hóa mọi thứ vì cả lý do công việc và hiệu suất.


0

Chà, một lợi ích chính có thể có của việc sử dụng chuỗi và các loại dữ liệu khác là gửi chúng từ SQL Server đến C #, C, C ++ (v.v.) bằng cách sử dụng SQLCLR khi có thể cần hiệu suất tuyệt đối. Bạn thậm chí có thể tạo chế độ xem hoặc thủ tục được lưu trữ để thể hiện dữ liệu quan hệ không liên quan - như bạn đã nêu ví dụ ở trên cho mục đích này.

Xem ví dụ này:

http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/

trên Wikipedia: SQL CLR hoặc SQLCLR (SQL Common Language Runtime) là công nghệ lưu trữ công cụ thời gian chạy ngôn ngữ chung Microsoft .NET trong SQL Server. SQLCLR cho phép mã được quản lý được lưu trữ bởi và chạy trong môi trường Microsoft SQL Server.


2
Chào bạn Bạn có thể vui lòng cho biết thêm chi tiết ở đây. Tôi không chắc làm thế nào đây là một lợi ích của việc lưu trữ dữ liệu theo những cách phi truyền thống. Nếu bất cứ điều gì, đó là một lợi ích của SQLCLR để có thể xử lý tốt hơn các định dạng dữ liệu thay thế nếu chúng phải tồn tại. Nhưng đó không phải là một lý do để thích một định dạng dữ liệu thay thế. Như vậy, tôi thực sự không nghĩ rằng câu trả lời này.
Solomon Rutzky

Liên kết bài viết giải thích những lợi ích với những ưu và nhược điểm. Ngoài ra, tôi đã đề cập đến việc lưu trữ dữ liệu một cách tương đối và vì mục đích của CLR chuyển đổi nó thành không liên quan với chế độ xem hoặc thủ tục được lưu trữ. Câu hỏi của bạn là "Sẽ có một kịch bản biện minh cho việc lưu trữ dữ liệu trong dòng (chuỗi) thay vì một vài dòng?" Và câu trả lời của tôi là có, mặc dù tôi thích một chế độ xem hoặc thủ tục được lưu trữ cho các mục đích tương tác với CLR.
Sting

0

Theo quan điểm của tôi, câu trả lời sẽ là không. Tôi đã không sử dụng phương pháp này và sẽ tránh nó - Tôi không thể nghĩ ra lý do tại sao tôi đi theo con đường đó. Bạn đang nghiêng về thế giới của JSON / NoQuery với một mảng.

Chúng tôi đã có các lựa chọn thiết kế tương tự trong một vai trò trước đó, theo đó nhóm kiến ​​trúc sư muốn có trường "Dữ liệu" được phân định và sau đó được chuyển đổi thành nhị phân. Chúng tôi đã không đi xuống tuyến đường đó cuối cùng vì một vài lý do.

Nếu bạn phải tham gia loại dữ liệu này, đó sẽ là một trải nghiệm xấu xí. Cập nhật các yếu tố duy nhất của chuỗi cũng sẽ khó chịu.

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.