2012-06-25 31 views
5

Tôi đang triển khai dịch vụ mà mỗi người dùng phải có cơ sở dữ liệu json/tài liệu của riêng mình. Ngoài việc cho phép người dùng truy vấn các tài liệu json bằng ví dụ, cơ sở dữ liệu cũng phải hỗ trợ các giao dịch ACID liên quan đến nhiều tài liệu, vì vậy tôi đã loại bỏ sử dụng Couch/Mongo hoặc các cơ sở dữ liệu NoSQL khác (không thể sử dụng RavenDB vì nó phải chạy trên các hệ thống Unix).Cần một cách hiệu quả để lưu trữ/truy vấn json trong cơ sở dữ liệu SQL

Với ý nghĩ đó, tôi đã cố gắng tìm ra cách để thực hiện điều đó trên cơ sở dữ liệu SQL. Dưới đây là những gì tôi đã đưa ra cho đến nay:

CREATE TABLE documents (
    id INTEGER PRIMARY KEY, 
    doc TEXT 
); 

CREATE TABLE indexes (
    id INTEGER PRIMARY KEY, 
    property TEXT, 
    value TEXT, 
    document_id INTEGER 
) 

Mỗi người dùng sẽ có một cơ sở dữ liệu với hai bảng này, và người dùng sẽ phải khai báo các trường ông cần để truy vấn vì vậy hệ thống đúng cách có thể cư trú trong 'Chỉ số ' bàn. Vì vậy, nếu người dùng 'A' cấu hình tài khoản của mình để bật truy vấn theo 'tên' và 'tuổi', mọi người dùng chèn tài liệu có thuộc tính 'tên' hoặc 'tuổi' hệ thống cũng sẽ chèn bản ghi vào 'chỉ mục' bảng, trong đó cột 'thuộc tính' sẽ chứa tên/tuổi, 'giá trị' sẽ chứa giá trị thuộc tính và 'document_id' sẽ trỏ đến tài liệu tương ứng.

Ví dụ, giả sử người dùng chèn doc sau:

'{"name" : "Foo", "age" 43}' 

này sẽ cho kết quả trong một chèn vào bảng 'tài liệu' và hai chèn nhiều vào bảng 'chỉ':

INSERT INTO documents (id,doc) VALUES (1, '{"name" : "Foo", "age" 43}'); 
INSERT INTO indexes (property, value, document_id) VALUES ('name', 'foo', 1); 
INSERT INTO indexes (property, value, document_id) VALUES ('age', '43', 1); 

sau đó, chúng ta hãy nói rằng người dùng 'A' gửi các dịch vụ truy vấn sau đây:

'{"name": "Foo", "age": 43}' //(the queries are also json documents). 

truy vấn này sẽ được dịch sang SQL sau đây:

SELECT doc FROM documents 
WHERE id IN (SELECT document_id FROM indexes 
      WHERE document_id IN (SELECT document_id FROM indexes 
            WHERE property = 'name' AND value = 'Foo') 
      AND property = 'age' AND value = '43') 

Câu hỏi của tôi:

  • Biết rằng người dùng có thể sử dụng một số lượng lớn các điều kiện trong các truy vấn của mình (cho phép nói 20-30 VÀ điều kiện), mà sẽ gây ra truy vấn con làm tổ rất cao, truy vấn SELECT ở trên có hiệu quả như thế nào trên hầu hết các hệ thống cơ sở dữ liệu (postgres, mysql ...)?
  • Giải pháp trên có khả thi cho một cơ sở dữ liệu mà cuối cùng sẽ chứa hàng triệu/tỷ tài liệu json không?
  • Có cách nào tốt hơn để đáp ứng các yêu cầu của tôi không?
  • Có cơ sở dữ liệu tài liệu có thể mở rộng nào có thể thực hiện các giao dịch ACID liên quan đến nhiều tài liệu và chạy trên các hệ thống Unix không?
+0

PostgreSQL 9.2 sẽ hỗ trợ loại dữ liệu JSON và với một số chức năng (ví dụ: được viết bằng JavaScript) ở trên có thể thực hiện được. Xem ở đây cho một ví dụ: http://people.planetpostgresql.org/andrew/index.php?/archives/249-Using-PLV8-to-index-JSON.html –

+0

Xem liệu CouchDB có hoạt động cho bạn không: "CouchDB cung cấp ACID ngữ nghĩa. Nó thực hiện điều này bằng cách thực hiện một hình thức kiểm soát đồng thời nhiều phiên bản, có nghĩa là CouchDB có thể xử lý một khối lượng lớn các độc giả đồng thời và các nhà văn mà không xung đột. " –

+0

Mẹo thú vị về PostgreSQL, tôi sẽ kiểm tra nó, nhờ –

Trả lời

5

Bảng indexes của bạn là cái được gọi là Entity-Attribute-Value.

Bảng EAV là tốt để lưu trữ thông tin và gọi lại khi bạn biết thực thể. (Trong trường hợp của bạn, việc tìm kiếm tất cả các indexes hàng khi bạn biết document_id.)

Nhưng họ khủng khiếp cách khác xung quanh: Cung cấp kết hợp Attribute-Value để tìm kiếm một thực thể. Đó là chính xác những gì bạn có trong truy vấn cuối cùng của mình. Vì ngày càng có nhiều thực thể chia sẻ các kết hợp thuộc tính-giá trị giống nhau (chẳng hạn như name=foo) hiệu suất truy vấn giảm xuống.

Vì vậy, để trả lời hai câu hỏi đầu tiên của bạn:
1. Các truy vấn, như viết tay, đòi hỏi n phụ truy vấn khi tìm kiếm n tài sản. Điều này sẽ mở rộng rất kém khi phát triển n.
2. Khi số lượng bản ghi tăng lên, nó sẽ bị suy giảm, đặc biệt là với hàng triệu bản ghi.

Nói chung, nếu bạn đọc khoảng EAV, mọi người khuyên bạn nên tránh xa nó.


Và, tệ hơn nữa, thực sự không có sự lựa chọn nào tốt trong SQL. Cách tiêu chuẩn để tối ưu hóa tìm kiếm là với chỉ mục, có thể dễ dàng được mô hình hóa dưới dạng tập dữ liệu được sắp xếp. Nhưng sau đó bạn sẽ cần nhiều chỉ mục:
- Chỉ mục trên (fieldX, fieldY, fieldZ)tuyệt vời nếu bạn tìm kiếm trên cả ba cột.
- Nhưng nó hút nếu bạn phải tìm kiếm trên chỉfieldZ.


Nếu bạn có thể tái mô hình này với một bảng truyền thống, với một số lượng cố định các cột, và có không gian để áp dụng tất cả các kết hợp chỉ số bạn lại phải cần, đó sẽ là bạn performant nhất mô hình.

Nếu bạn không thể sửa số cột (mới properties đến cùng mọi lúc) và/hoặc bạn không có không gian cho tất cả các kết hợp khác nhau của chỉ mục, bạn dường như bị kẹt với EAV. Điều này sẽ hoạt động, nhưng nó sẽ không phải là quy mô rất tốt về kết quả 'tức thời'.

LƯU Ý: Nếu bạn gắn bó với EAV, bạn đã thử nghiệm cấu trúc truy vấn này chưa?

SELECT 
    document_id 
    FROM 
    indexes 
    WHERE 
     (property = 'name' AND value = 'Foo') 
    OR (property = 'age' AND value = '43') 
    GROUP BY 
    document_id 
    HAVING 
    COUNT(*) = 2 

Giả định rằng (document_id, property, value) là duy nhất. Nếu không, một tài liệu có thể có ('name', 'foo') hai lần và vì vậy, hãy chuyển mệnh đề COUNT(*).

+0

Tôi không nghĩ rằng bảng 'chỉ mục' đang lập mô hình dữ liệu bằng cách sử dụng phương pháp 'Thuộc tính-Giá trị thuộc tính', chỉ là một cách để dữ liệu sơ đồ chỉ mục 'thủ công' trong bảng 'tài liệu'. Tôi quên đề cập đến rằng các cột tên và giá trị cũng sẽ được lập chỉ mục, bạn không nghĩ rằng sẽ làm cho các truy vấn chạy nhanh? –

+1

@ThiadodeArruda - Thật không may, nó chính xác là EAV. 'Tài liệu' của bạn là' Thực thể'. 'Thuộc tính' của bạn là' Thuộc tính'. Và 'Giá trị' của bạn là, tốt, tôi nghĩ bạn có được điểm đó. Lập chỉ mục '(thuộc tính, giá trị, document_id)' chắc chắn sẽ cải thiện mọi thứ so với việc không làm nó, nhưng đó là một giả định làm việc tối thiểu. Bạn vẫn có tất cả những khó khăn của EAV. Nó sẽ luôn chậm hơn đáng kể so với bảng 'truyền thống'.Và càng nhiều bản ghi chia sẻ cùng một giá trị cho bất kỳ thuộc tính cụ thể nào, thì bản ghi sẽ càng chậm. Và càng có nhiều thuộc tính bạn tìm kiếm, chậm hơn. – MatBailie

Các vấn đề liên quan