Làm cách nào để thiết kế cơ sở dữ liệu cho các trường do người dùng xác định?


145

Yêu cầu của tôi là:

  • Cần có khả năng tự động thêm các trường do Người dùng xác định thuộc bất kỳ loại dữ liệu nào
  • Cần có khả năng truy vấn UDF nhanh chóng
  • Cần có khả năng tính toán trên UDF dựa trên kiểu dữ liệu
  • Cần có khả năng sắp xếp UDF dựa trên kiểu dữ liệu

Thông tin khác:

  • Tôi đang tìm kiếm hiệu suất chủ yếu
  • Có một vài triệu bản ghi Master có thể có dữ liệu UDF được đính kèm
  • Khi tôi kiểm tra lần cuối, có hơn 50 triệu bản ghi UDF trong cơ sở dữ liệu hiện tại của chúng tôi
  • Hầu hết thời gian, một UDF chỉ được đính kèm với một vài ngàn hồ sơ Master, không phải tất cả chúng
  • UDF không được nối hoặc sử dụng làm khóa. Chúng chỉ là dữ liệu được sử dụng cho truy vấn hoặc báo cáo

Tùy chọn:

  1. Tạo một bảng lớn với StringValue1, StringValue2 ... IntValue1, IntValue2, ... vv Tôi ghét ý tưởng này, nhưng sẽ xem xét nó nếu ai đó có thể cho tôi biết nó tốt hơn những ý tưởng khác và tại sao.

  2. Tạo một bảng động có thêm một cột mới theo yêu cầu khi cần thiết. Tôi cũng không thích ý tưởng này vì tôi cảm thấy hiệu suất sẽ chậm trừ khi bạn lập chỉ mục cho mỗi cột.

  3. Tạo một bảng duy nhất chứa UDFName, UDFDataType và Value. Khi UDF mới được thêm vào, hãy tạo Chế độ xem chỉ lấy dữ liệu đó và phân tích nó thành bất kỳ loại nào được chỉ định. Các mục không đáp ứng tiêu chí phân tích cú pháp sẽ trả về NULL.

  4. Tạo nhiều bảng UDF, mỗi bảng một kiểu dữ liệu. Vì vậy, chúng tôi sẽ có các bảng cho UDFStrings, UDFDates, v.v. Có lẽ sẽ làm tương tự như # 2 và tự động tạo Chế độ xem bất cứ khi nào một trường mới được thêm vào

  5. Dữ liệu XML? Tôi đã không làm việc với những điều này trước đây nhưng đã thấy chúng được đề cập. Không chắc họ có cho tôi kết quả tôi muốn hay không, đặc biệt là với hiệu suất.

  6. Thứ gì khác?


7
Martin Fowler đề xuất 2 (lược đồ có thể cập nhật cho người dùng) hoặc 5 (LOB XML được lập chỉ mục): martinfowler.com/bliki/UserDefinedField.html
Neil McGuigan

Xem thêm câu hỏi StackOverflow trên các lược đồ cơ sở dữ liệu động .
FloverOwe

Câu trả lời:


49

Nếu hiệu suất là mối quan tâm chính, tôi sẽ đi với # 6 ... một bảng cho mỗi UDF (thực sự, đây là một biến thể của # 2). Câu trả lời này được thiết kế riêng cho tình huống này và mô tả phân phối dữ liệu và các mẫu truy cập được mô tả.

Ưu điểm:

  1. Vì bạn chỉ ra rằng một số UDF có giá trị cho một phần nhỏ của tập dữ liệu tổng thể, một bảng riêng biệt sẽ cung cấp cho bạn hiệu suất tốt nhất vì bảng đó sẽ chỉ lớn bằng mức cần thiết để hỗ trợ UDF. Điều tương tự cũng đúng với các chỉ số liên quan.

  2. Bạn cũng có thể tăng tốc độ bằng cách giới hạn số lượng dữ liệu phải được xử lý cho các tập hợp hoặc các biến đổi khác. Việc chia dữ liệu thành nhiều bảng cho phép bạn thực hiện một số phân tích thống kê và tổng hợp khác trên dữ liệu UDF, sau đó nối kết quả đó với bảng chính thông qua khóa ngoài để có được các thuộc tính không tổng hợp.

  3. Bạn có thể sử dụng tên bảng / cột phản ánh dữ liệu thực sự là gì.

  4. Bạn có toàn quyền kiểm soát để sử dụng các loại dữ liệu, kiểm tra các ràng buộc, giá trị mặc định, v.v. để xác định miền dữ liệu. Đừng đánh giá thấp hiệu suất đạt được do chuyển đổi loại dữ liệu nhanh chóng. Các ràng buộc như vậy cũng giúp tối ưu hóa truy vấn RDBMS phát triển các kế hoạch hiệu quả hơn.

  5. Nếu bạn cần sử dụng khóa ngoại, tính toàn vẹn tham chiếu khai báo được tích hợp hiếm khi được thực hiện bằng cách thực thi ràng buộc ở cấp độ kích hoạt hoặc dựa trên ứng dụng.

Nhược điểm:

  1. Điều này có thể tạo ra rất nhiều bảng. Việc thực thi tách lược đồ và / hoặc quy ước đặt tên sẽ làm giảm bớt điều này.

  2. Có nhiều mã ứng dụng cần thiết hơn để vận hành định nghĩa và quản lý UDF. Tôi hy vọng đây vẫn là ít mã cần thiết hơn so với các tùy chọn ban đầu 1, 3, & 4.

Những ý kiến ​​khác:

  1. Nếu có bất cứ điều gì về bản chất của dữ liệu sẽ có ý nghĩa đối với các UDF được nhóm lại, điều đó nên được khuyến khích. Bằng cách đó, các yếu tố dữ liệu có thể được kết hợp thành một bảng duy nhất. Ví dụ: giả sử bạn có UDF về màu sắc, kích thước và chi phí. Xu hướng của dữ liệu là hầu hết các trường hợp của dữ liệu này trông giống như

     'red', 'large', 45.03 

    thay vì

     NULL, 'medium', NULL

    Trong trường hợp như vậy, bạn sẽ không phải chịu một hình phạt tốc độ đáng chú ý bằng cách kết hợp 3 cột trong 1 bảng vì một vài giá trị sẽ là NULL và bạn tránh tạo thêm 2 bảng, cần ít hơn 2 liên kết khi bạn cần truy cập cả 3 cột .

  2. Nếu bạn nhấn một bức tường hiệu suất từ ​​UDF có dân số đông và thường xuyên sử dụng, thì điều đó nên được xem xét để đưa vào bảng chính.

  3. Thiết kế bảng logic có thể đưa bạn đến một điểm nhất định, nhưng khi số lượng bản ghi thực sự lớn, bạn cũng nên bắt đầu xem xét các tùy chọn phân vùng bảng nào được cung cấp bởi RDBMS của bạn.


1
Danh sách kiểm tra! Trò đùa bên trong tôi và Phil, tôi hy vọng điều đó không trái với quy tắc.
GunnerL3510

Cảm ơn, tôi nghĩ rằng tôi sẽ làm một số biến thể của điều này. Hầu hết dữ liệu UDF của chúng tôi đến từ các trường nhập chưa được ánh xạ, chỉ cần lưu lại cho mục đích tham khảo, vì vậy tôi muốn đặt chúng vào một bảng. Các UDF khác được định nghĩa là cần thiết (tôi không thể xác định trước chúng .. chúng thường được tạo khi chúng tôi thay đổi một số quy trình hoặc quyết định theo dõi một cái gì đó đặc biệt trong vài tháng) và thường được sử dụng trong các truy vấn. Tôi nghĩ rằng tôi sẽ tạo một bảng riêng cho từng đơn vị logic của các giá trị này.
Rachel

Tôi đang làm việc với một bảng đã ghi ngày / phiên bản của UDF, tôi sử dụng phương thức này, stackoverflow.com/a/123481/328968 , để có được các giá trị mới nhất.
Peter

22

Tôi đã viết về vấn đề này rất nhiều . Giải pháp phổ biến nhất là antipotype Entity-Attribution-Value, tương tự như những gì bạn mô tả trong tùy chọn # 3 của bạn. Tránh thiết kế này giống như bệnh dịch hạch .

Những gì tôi sử dụng cho giải pháp này khi tôi cần các trường tùy chỉnh thực sự năng động là lưu trữ chúng trong một blob XML, vì vậy tôi có thể thêm các trường mới bất cứ lúc nào. Nhưng để làm cho nó nhanh hơn, hãy tạo các bảng bổ sung cho từng trường bạn cần tìm kiếm hoặc sắp xếp (bạn không phải là một bảng cho mỗi trường - chỉ là một bảng cho mỗi trường có thể tìm kiếm ). Điều này đôi khi được gọi là một thiết kế chỉ mục đảo ngược.

Bạn có thể đọc một bài viết thú vị từ năm 2009 về giải pháp này tại đây: http://backchannel.org/blog/friendfeed-schemaless-mysql

Hoặc bạn có thể sử dụng cơ sở dữ liệu hướng tài liệu, nơi dự kiến ​​bạn có các trường tùy chỉnh cho mỗi tài liệu. Tôi sẽ chọn Solr .


1
Bạn có thể giải thích tại sao tôi nên tránh lựa chọn số 3 không? Tôi đã xem xét một số ví dụ của bạn, nhưng chúng thực sự không giống với những gì tôi đang cố gắng làm. Tôi chỉ đơn giản muốn một nơi để lưu trữ dữ liệu bổ sung, không phải là nơi lưu trữ tất cả các thuộc tính.
Rachel

2
Để bắt đầu, bạn sẽ tạo một thuộc tính KHÔNG NULL? Làm thế nào bạn có thể tạo một thuộc tính ĐỘC ĐÁO mà không tạo ra tất cả các thuộc tính ĐỘC ĐÁO? Nó tiếp tục từ đó. Bạn kết thúc việc viết mã ứng dụng để cung cấp các tính năng mà RDBMS đã cung cấp cho bạn, thậm chí đến mức phải viết một loại lớp ánh xạ nào đó chỉ đơn giản là chèn một bản ghi thực thể logic và tìm nạp lại.
Bill Karwin

2
Câu trả lời ngắn gọn là "không trộn dữ liệu và siêu dữ liệu." Tạo các cột varchar cho fieldnamehoặc tablenameđang lưu trữ số nhận dạng siêu dữ liệu dưới dạng chuỗi dữ liệu và đó là khởi đầu của rất nhiều vấn đề. Đồng thời xem en.wikipedia.org/wiki/Inner-pl platform_effect
Bill Karwin

2
@Thomas: Trong thiết kế chỉ mục đảo ngược, bạn có thể sử dụng các giải pháp lược đồ tiêu chuẩn cho các loại dữ liệu và các ràng buộc như UNIQUE và FOREIGN KEY. Những thứ đó không hoạt động khi bạn sử dụng EAV. Tôi đồng ý chia sẻ chỉ mục ngược với EAV đặc điểm là không liên quan đơn giản vì nó hỗ trợ các thuộc tính không giống nhau trên mỗi hàng, nhưng đó là một điểm thỏa hiệp.
Bill Karwin

2
@thitami, Điều tôi đã học được trong nhiều năm qua là bất kỳ giải pháp nào cũng có thể là giải pháp phù hợp cho ứng dụng của bạn. Ngay cả EAV có thể là giải pháp kém nhất cho một số ứng dụng cụ thể. Bạn không thể chọn một chiến lược tối ưu hóa mà không biết các truy vấn của mình. Mỗi loại tối ưu hóa đều cải thiện các truy vấn nhất định với chi phí của các truy vấn khác.
Bill Karwin

10

Tôi hầu như có thể tạo một bảng cấu trúc sau:

  • tên varchar
  • loại varar
  • số thập phânValue
  • varchar StringValue
  • ngày DateValue

Các loại khóa học chính xác phụ thuộc vào nhu cầu của bạn (và tất nhiên dựa trên dbms bạn đang sử dụng). Bạn cũng có thể sử dụng trường NumberValue (thập phân) cho int và booleans. Bạn có thể cần các loại khác là tốt.

Bạn cần một số liên kết đến các bản ghi Master sở hữu giá trị. Có thể dễ nhất và nhanh nhất để tạo bảng trường người dùng cho mỗi bảng chính và thêm khóa ngoại đơn giản. Bằng cách này, bạn có thể lọc các bản ghi chính theo trường người dùng một cách dễ dàng và nhanh chóng.

Bạn có thể muốn có một số loại thông tin dữ liệu meta. Vì vậy, bạn kết thúc với những điều sau đây:

Bảng UdfMetaData

  • int id
  • tên varchar
  • loại varar

Bảng MasterUdfValues

  • int Master_FK
  • int MetaData_FK
  • số thập phânValue
  • varchar StringValue
  • ngày DateValue

Dù bạn làm gì, tôi sẽ không thay đổi cấu trúc bảng một cách linh hoạt. Đó là một cơn ác mộng bảo trì. Tôi cũng sẽ không sử dụng các cấu trúc XML, chúng quá chậm.


Tôi thích chiến lược của bạn, và có thể chọn cho nó nhưng năm 2017, bạn sẽ chọn một cái gì đó khác biệt? như json
maztt

Trong dự án của chúng tôi, chúng tôi đã triển khai các cấu trúc dữ liệu của riêng mình, nối tiếp với một thứ tương tự như json. Nó có giao diện sắp chữ để đọc và ghi dữ liệu mà không cần truyền và tích hợp ngôn ngữ lập trình tuyệt vời. Điều đó thực sự tuyệt vời. Nó có cùng một vấn đề như tất cả các loại "tài liệu" này trong cơ sở dữ liệu. Thật khó để truy vấn các giá trị spcific và nó không thể dễ dàng tham chiếu dữ liệu bên ngoài "tài liệu". Tùy thuộc vào cách sử dụng, cả hai thậm chí không phải là một vấn đề.
Stefan Steinegger

Bên cạnh đó, những gì tôi đề xuất trong năm 2011 là IMHO vẫn là một giải pháp hợp lệ.
Stefan Steinegger

10

Điều này có vẻ như là một vấn đề có thể được giải quyết tốt hơn bằng một giải pháp không liên quan, như MongoDB hoặc CouchDB.

Cả hai đều cho phép mở rộng lược đồ động trong khi cho phép bạn duy trì tính toàn vẹn của bộ dữ liệu mà bạn tìm kiếm.

Tôi đồng ý với Bill Karwin, mô hình EAV không phải là cách tiếp cận hiệu quả với bạn. Sử dụng các cặp tên-giá trị trong một hệ thống quan hệ về bản chất không phải là xấu, mà chỉ hoạt động tốt khi cặp giá trị tên tạo ra một bộ thông tin hoàn chỉnh. Khi sử dụng nó buộc bạn phải tự động xây dựng lại một bảng trong thời gian chạy, tất cả các loại bắt đầu khó khăn. Truy vấn trở thành một bài tập trong bảo trì trục hoặc buộc bạn phải đẩy cấu trúc lại lên lớp đối tượng.

Bạn không thể xác định xem giá trị null hoặc thiếu là mục nhập hợp lệ hay thiếu mục nhập mà không nhúng các quy tắc lược đồ trong lớp đối tượng của bạn.

Bạn mất khả năng quản lý hiệu quả lược đồ của bạn. Là một varchar 100 ký tự có phải là loại phù hợp cho trường "giá trị" không? 200 ký tự? Nó có nên là nvarchar thay thế? Nó có thể là một sự đánh đổi khó khăn và kết thúc bằng việc bạn phải đặt các giới hạn nhân tạo cho tính chất năng động của bộ ảnh của bạn. Một cái gì đó như "bạn chỉ có thể có x trường do người dùng xác định và mỗi trường chỉ có thể dài y ký tự.

Với giải pháp hướng tài liệu, như MongoDB hoặc CouchDB, bạn duy trì tất cả các thuộc tính được liên kết với người dùng trong một bộ dữ liệu. Vì tham gia không phải là một vấn đề, cuộc sống là hạnh phúc, vì cả hai đều không tốt với tham gia, mặc dù sự cường điệu. Người dùng của bạn có thể xác định số lượng thuộc tính như họ muốn (hoặc bạn sẽ cho phép) ở độ dài không khó quản lý cho đến khi bạn đạt khoảng 4MB.

Nếu bạn có dữ liệu yêu cầu tính toàn vẹn ở cấp độ ACID, bạn có thể xem xét phân tách giải pháp, với dữ liệu toàn vẹn cao sống trong cơ sở dữ liệu quan hệ của bạn và dữ liệu động sống trong một cửa hàng không liên quan.


6

Ngay cả khi bạn cung cấp cho người dùng thêm các cột tùy chỉnh, sẽ không nhất thiết là trường hợp truy vấn trên các cột đó sẽ hoạt động tốt. Có nhiều khía cạnh đi vào thiết kế truy vấn cho phép chúng thực hiện tốt, trong đó quan trọng nhất là thông số kỹ thuật phù hợp về những gì nên được lưu trữ ở vị trí đầu tiên. Do đó, về cơ bản, có phải bạn muốn cho phép người dùng tạo lược đồ mà không cần suy nghĩ về thông số kỹ thuật và có thể nhanh chóng lấy được thông tin từ lược đồ đó không? Nếu vậy, thì thật không may là bất kỳ giải pháp nào như vậy sẽ có quy mô tốt, đặc biệt nếu bạn muốn cho phép người dùng thực hiện phân tích số trên dữ liệu.

lựa chọn 1

IMO phương pháp này cung cấp cho bạn lược đồ không có kiến ​​thức về lược đồ có nghĩa là công thức cho thảm họa và cơn ác mộng đối với các nhà thiết kế báo cáo. Tức là bạn phải có dữ liệu meta để biết cột nào lưu trữ dữ liệu gì. Nếu siêu dữ liệu đó bị rối tung, nó có khả năng làm hỏng dữ liệu của bạn. Thêm vào đó, nó dễ dàng đưa dữ liệu sai vào cột sai. ("Cái gì? String1 chứa tên của chứng nhận? Tôi nghĩ đó là loại thuốc yêu thích của Chalie Sheen.")

Tùy chọn 3,4,5

IMO, các yêu cầu 2, 3 và 4 loại bỏ mọi biến thể của EAV. Nếu bạn cần truy vấn, sắp xếp hoặc thực hiện các tính toán trên dữ liệu này, thì EAV là giấc mơ của Cthulhu và cơn ác mộng của nhóm phát triển và DBA của bạn. EAV sẽ tạo ra một nút cổ chai về hiệu suất và sẽ không cung cấp cho bạn tính toàn vẹn dữ liệu mà bạn cần để nhanh chóng có được thông tin bạn muốn. Các truy vấn sẽ nhanh chóng chuyển sang nút thắt Gordian.

Tùy chọn 2,6

Điều đó thực sự để lại một sự lựa chọn: thu thập các thông số kỹ thuật và sau đó xây dựng lược đồ.

Nếu khách hàng muốn có hiệu suất tốt nhất trên dữ liệu họ muốn lưu trữ, thì họ cần trải qua quá trình làm việc với nhà phát triển để hiểu nhu cầu của họ để nó được lưu trữ hiệu quả nhất có thể. Nó vẫn có thể được lưu trữ trong một bảng tách biệt với các bảng còn lại với mã tự động xây dựng một biểu mẫu dựa trên lược đồ của bảng. Nếu bạn có cơ sở dữ liệu cho phép các thuộc tính mở rộng trên các cột, bạn thậm chí có thể sử dụng các thuộc tính đó để giúp trình tạo biểu mẫu sử dụng nhãn đẹp, chú giải công cụ, v.v. để tất cả những gì cần thiết là thêm lược đồ. Dù bằng cách nào, để xây dựng và chạy các báo cáo hiệu quả, dữ liệu cần được lưu trữ đúng cách. Nếu dữ liệu trong câu hỏi sẽ có rất nhiều null, một số cơ sở dữ liệu có khả năng lưu trữ loại thông tin đó. Ví dụ,

Nếu đây chỉ là một túi dữ liệu mà không có phân tích, lọc hoặc sắp xếp nào được thực hiện, tôi sẽ nói rằng một số biến thể của EAV có thể thực hiện thủ thuật. Tuy nhiên, với các yêu cầu của bạn, giải pháp hiệu quả nhất sẽ là có được các thông số kỹ thuật phù hợp ngay cả khi bạn lưu trữ các cột mới này trong các bảng riêng biệt và xây dựng các biểu mẫu tự động khỏi các bảng đó.

Cột thưa thớt


5
  1. Tạo nhiều bảng UDF, mỗi bảng một kiểu dữ liệu. Vì vậy, chúng tôi sẽ có các bảng cho UDFStrings, UDFDates, v.v. Có lẽ sẽ làm tương tự như # 2 và tự động tạo Chế độ xem bất cứ khi nào một trường mới được thêm vào

Theo nghiên cứu của tôi, nhiều bảng dựa trên kiểu dữ liệu sẽ không giúp bạn thực hiện. Đặc biệt nếu bạn có dữ liệu số lượng lớn, như các bản ghi 20K hoặc 25K với hơn 50 UDF. Hiệu suất là tồi tệ nhất.

Bạn nên đi với một bảng có nhiều cột như:

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue

Điều này nên là một chính xác và nâng cao. Câu trả lời trước vào năm 2011 của Phil không còn là một lời khuyên hay vào ngày hôm nay 2016.
Yap Kai Lun Leon

Tôi có thể lấy một ví dụ đơn giản về cách thực hiện quy trình như vậy trong sql.?
Niroj

Xin lỗi vì đã trả lời trễ, nhưng bạn muốn cấu trúc cơ sở dữ liệu giống nhau. Tôi không hiểu bạn @Niroj. Bạn có thể vui lòng giải thích chi tiết như những gì bạn muốn.
Nhà thầu Amit

4

Đây là một tình huống có vấn đề và không có giải pháp nào xuất hiện "đúng". Tuy nhiên tùy chọn 1 có lẽ là tốt nhất cả về sự đơn giản và về hiệu suất.

Đây cũng là giải pháp được sử dụng trong một số ứng dụng doanh nghiệp thương mại.

BIÊN TẬP

một tùy chọn khác hiện có sẵn, nhưng không tồn tại (hoặc ít nhất là chưa trưởng thành) khi câu hỏi ban đầu được hỏi là sử dụng các trường json trong DB.

nhiều DB quan hệ hiện hỗ trợ các trường dựa trên json (có thể bao gồm danh sách động của các trường con) và cho phép truy vấn chúng

hoãn

mys


1
Tôi ghét ý tưởng tạo ra hàng trăm cột không sử dụng. Nó đi ngược lại những gì tôi đã học và đọc về thiết kế cơ sở dữ liệu SQL. Ngay bây giờ, chúng tôi có hơn 1300 giá trị do người dùng xác định khác nhau, mặc dù rất nhiều trong số chúng chỉ là bản sao của các mục hiện có được đặt tên khác nhau.
Rachel

1300 UDF khác nhau cho một bảng duy nhất? mỗi người dùng có tùy chọn để thêm UDF, hoặc chỉ một số loại người dùng quyền lực?
Ophir Yoktan

Đó là một phần của quy trình nhập ... nó thêm bất kỳ dữ liệu không được ánh xạ nào vào trường do người dùng xác định. Vì không ai dành thời gian để ánh xạ dữ liệu chưa được ánh xạ vào các trường UDF hiện tại, nó chỉ tạo ra những dữ liệu mới và qua nhiều năm đã được thêm vào.
Rachel

2

Tôi đã có kinh nghiệm hoặc 1, 3 và 4 và tất cả đều kết thúc lộn xộn, với việc không rõ dữ liệu là gì hoặc thực sự phức tạp với một số loại phân loại mềm để chia dữ liệu thành các loại bản ghi động.

Tôi muốn thử dùng XML, bạn sẽ có thể thực thi các lược đồ đối với nội dung của xml để kiểm tra việc nhập dữ liệu, v.v ... điều này sẽ giúp giữ các bộ dữ liệu UDF khác nhau. Trong các phiên bản mới hơn của máy chủ SQL, bạn có thể lập chỉ mục trên các trường XML, điều này sẽ giúp cải thiện hiệu suất. (xem http://bloss.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ) chẳng hạn


Thành thật mà nói, tôi chưa nhìn vào XML. Nhược điểm chính của điều đó là tôi phải tìm hiểu cách thức hoạt động và cách truy vấn nó, và tôi đã nghe hiệu suất có thể tệ hơn các tùy chọn khác
Rachel

1
Tôi đã tránh sử dụng xml cho việc này: nó có thể thực hiện công việc và tôi đã thực hiện đôi khi như thế này trong xml trước đây, nhưng hiệu suất khá tệ khi cấu trúc dữ liệu tăng lên và độ phức tạp của mã cao.
Kell

2

Nếu bạn đang sử dụng SQL Server, đừng bỏ qua loại sqlvariant. Nó khá nhanh và nên làm công việc của bạn. Các cơ sở dữ liệu khác có thể có một cái gì đó tương tự.

Các kiểu dữ liệu XML không tốt lắm vì lý do hiệu năng. Nếu bạn đang thực hiện các tính toán trên máy chủ thì bạn liên tục phải giải tuần tự hóa chúng.

Tùy chọn 1 nghe có vẻ tệ và có vẻ hỗn độn, nhưng hiệu suất khôn ngoan có thể là lựa chọn tốt nhất của bạn. Tôi đã tạo các bảng có các cột có tên Field00-Field99 trước đây vì bạn không thể đánh bại hiệu suất. Bạn cũng có thể cần phải xem xét hiệu suất INSERT của mình, trong trường hợp này đây cũng là một trong những thứ phù hợp. Bạn luôn có thể tạo Lượt xem trên bảng này nếu bạn muốn nó trông gọn gàng!


Cảm ơn, tôi sẽ xem xét lại các biến thể SQL. Mối quan tâm lớn nhất của tôi là hiệu suất và tôi không chắc nó sẽ xử lý việc đó như thế nào, đặc biệt nếu chúng ta đang nói về hơn 50 triệu hàng
Rachel

Chỉ cần tìm ra sql_varients không thể được sử dụng với mệnh đề THÍCH ... đó là một nhược điểm rất lớn đối với tôi. Tất nhiên, nếu tôi tạo chế độ xem cho mỗi UDF thì tôi có thể chuyển nó thành kiểu dữ liệu phù hợp dựa trên SQL_VariANT_PROPERTY (giá trị, 'BaseType') ... có vẻ như nó không tốt cho hiệu suất
Rachel

Bạn có thể sử dụng THÍCH, nhưng bạn phải bỏ giá trị trước. THÍCH chỉ hoạt động trên varchars vì vậy bạn phải truyền sql_variant của bạn thành varchar. Miễn là bạn biết liệu UDF của bạn có phải là một varchar hay không (ví dụ: vì loại được lưu trữ ở một nơi khác), bạn có thể lọc tất cả các hàng của mình thành varchars sau đó truyền và chạy truy vấn THÍCH của bạn: vd. chọn * TỪ MyTable trong đó biến thể_type = 'v' Truyền (biến_value là varchar (tối đa)) THÍCH 'Blah%' Bằng cách này, bạn không chuyển đổi ints và cứ thế chuyển sang chuỗi làm chậm bạn.
Tim Rogers

Tôi cần chạy một số thử nghiệm để xem hiệu suất của nó như thế nào, đặc biệt là với hàng triệu hàng. Bạn có biết bất kỳ bài viết trực tuyến nào về hiệu suất sử dụng sql_varients không? Đặc biệt với việc đúc và số lượng hồ sơ rất lớn?
Rachel


1

Tôi đã quản lý việc này rất thành công trong quá khứ bằng cách không sử dụng bất kỳ tùy chọn nào trong số này (tùy chọn 6? :)).

Tôi tạo một mô hình cho người dùng chơi (lưu trữ dưới dạng xml và hiển thị thông qua một công cụ mô hình hóa tùy chỉnh) và từ các bảng và khung nhìn được tạo mô hình để nối các bảng cơ sở với các bảng dữ liệu do người dùng xác định. Vì vậy, mỗi loại sẽ có một bảng cơ sở với dữ liệu cốt lõi và bảng người dùng với các trường do người dùng xác định.

Lấy một tài liệu làm ví dụ: các trường điển hình sẽ là tên, loại, ngày, tác giả, v.v ... Điều này sẽ đi vào bảng cốt lõi. Sau đó, người dùng sẽ xác định các loại tài liệu đặc biệt của riêng họ với các trường riêng của họ, chẳng hạn như hợp đồng_end_date, đổi mới_clause, blah blah blah. Đối với tài liệu do người dùng định nghĩa đó, sẽ có bảng tài liệu lõi, bảng xcontract, được nối trên một khóa chính chung (vì vậy khóa chính xcontract cũng nằm ngoài khóa chính của bảng lõi). Sau đó, tôi sẽ tạo ra một khung nhìn để bọc hai bảng này. Hiệu suất khi truy vấn nhanh. quy tắc kinh doanh bổ sung cũng có thể được nhúng vào các khung nhìn. Điều này làm việc thực sự tốt cho tôi.


1

Cơ sở dữ liệu của chúng tôi cung cấp ứng dụng SaaS (phần mềm trợ giúp) nơi người dùng có hơn 7k "trường tùy chỉnh". Chúng tôi sử dụng một phương pháp kết hợp:

  1. (EntityID, FieldID, Value)bảng để tìm kiếm dữ liệu
  2. một trường JSON trong entitiesbảng, chứa tất cả các giá trị thực thể, được sử dụng để hiển thị dữ liệu. (theo cách này bạn không cần một triệu THAM GIA để có được các giá trị giá trị).

Bạn có thể chia thêm # 1 để có "bảng cho mỗi kiểu dữ liệu" như câu trả lời này gợi ý, theo cách này, bạn thậm chí có thể lập chỉ mục UDF của mình.

PS Vài từ để bảo vệ cách tiếp cận "Thực thể-Thuộc tính-Giá trị" mà mọi người cứ bực bội. Chúng tôi đã sử dụng # 1 mà không # 2 trong nhiều thập kỷ và nó hoạt động tốt. Đôi khi đó là một quyết định kinh doanh. Bạn có thời gian để viết lại ứng dụng của mình và thiết kế lại db hoặc bạn có thể ném một vài đô la vào các máy chủ đám mây, những thứ thực sự rẻ trong những ngày này không? Nhân tiện, khi chúng tôi sử dụng phương pháp số 1, DB của chúng tôi đang nắm giữ hàng triệu thực thể, được truy cập bởi hàng trăm ngàn người dùng và máy chủ db lõi kép 16 GB đang hoạt động tốt


Xin chào @Alex, tôi đã gặp một vấn đề tương tự. Nếu tôi hiểu rõ bạn đã có: 1) một custom_fieldsbảng lưu các giá trị như 1 => last_concert_year, 2 => band, 3 => musicvà sau đó một custom_fields_valuesbảng có các giá trị 001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 , Metal Hy vọng ví dụ này có ý nghĩa với bạn và xin lỗi vì định dạng!
thitami

@thitami không chính xác. Theo ví dụ của bạn: Tôi có một bandsbảng có một hàng 1,'Iron Maiden'sau đó custom_fieldsvới các hàng 1,'concert_year' | 2,'music'sau đó custom_fields_valuesvới các hàng1,1,'1977'|1,2,'metal'
Alex

0

Trong các bình luận tôi thấy bạn nói rằng các trường UDF sẽ kết xuất dữ liệu đã nhập không được người dùng ánh xạ đúng.

Có lẽ một tùy chọn khác là theo dõi số lượng UDF được tạo bởi mỗi người dùng và buộc họ sử dụng lại các trường bằng cách nói rằng họ có thể sử dụng 6 (hoặc một số giới hạn ngẫu nhiên tương đương khác).

Khi bạn gặp phải vấn đề cấu trúc cơ sở dữ liệu như thế này, tốt nhất là quay lại thiết kế cơ bản của ứng dụng (hệ thống nhập trong trường hợp của bạn) và đặt thêm một vài hạn chế cho nó.

Bây giờ những gì tôi sẽ làm là tùy chọn 4 (EDIT) với việc thêm liên kết đến người dùng:

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

Bây giờ hãy đảm bảo tạo các khung nhìn để tối ưu hóa hiệu suất và lấy chỉ mục của bạn đúng. Mức chuẩn hóa này làm cho dấu chân DB nhỏ hơn, nhưng ứng dụng của bạn phức tạp hơn.


0

Tôi muốn giới thiệu # 4 vì loại hệ thống này đã được sử dụng trong Magento , một nền tảng CMS thương mại điện tử được công nhận cao. Sử dụng một bảng duy nhất để xác định các trường tùy chỉnh của bạn bằng cách sử dụng các cột fieldId & nhãn . Sau đó, có các bảng riêng biệt cho từng loại dữ liệu và trong mỗi bảng đó có một chỉ mục được lập chỉ mục theo trườngId và các cột giá trị loại dữ liệu . Sau đó, trong các truy vấn của bạn, sử dụng một cái gì đó như:

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

Điều này sẽ đảm bảo hiệu suất tốt nhất có thể cho các loại do người dùng xác định theo ý kiến ​​của tôi.

Theo kinh nghiệm của tôi, tôi đã làm việc trên một số trang web Magento phục vụ hàng triệu người dùng mỗi tháng, lưu trữ hàng ngàn sản phẩm có thuộc tính sản phẩm tùy chỉnh và cơ sở dữ liệu xử lý khối lượng công việc dễ dàng, ngay cả để báo cáo.

Để báo cáo, bạn có thể sử dụng PIVOTđể chuyển đổi giá trị nhãn bảng Trường của mình thành tên cột, sau đó xoay vòng kết quả truy vấn của bạn từ mỗi bảng loại dữ liệu thành các cột được xoay vòng.

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.