Có thể có hai bản sao của một bảng được sắp xếp một cách liền mạch không?


7

Tôi có một bảng với khoảng 100 triệu hàng. Nó chỉ được chèn dữ liệu một lần / ngày nhưng chúng ta cần phải làm selectrất nhiều. Các selects thường đơn giản nhưng đôi khi cần trả về hàng trăm ngàn hàng.

Đó là độc đáo dựa trên ba cột node_id, pricedate, hourđó là số nguyên, dấu thời gian, số nguyên tương ứng. Đó là chậm đối với hầu hết các truy vấn nhưng tôi nhóm nó node_id, pricedatevà đó cố định chậm đối với hầu hết các truy vấn. Những truy vấn đó thuộc loại:

select * from mytable where node_id in (1,2,3,4)

Thỉnh thoảng chúng tôi vẫn cần thực hiện các truy vấn như:

select * from mytable where pricedate>='2016-05-01'

Những điều này vẫn còn chậm bởi vì nó được nhóm node_idtrước. Chúng tôi đã có một chỉ số trên pricedate. Vấn đề là người dùng thường cần đủ dữ liệu mà công cụ truy vấn ném ra chỉ mục và sử dụng quét seq. Khi nó sử dụng quét seq, nó có lợi rất nhiều từ việc dữ liệu được nhóm lại theo cách nó được truy vấn. Điều này dẫn đến vấn đề mà tôi gặp phải khi một số truy vấn được hưởng lợi từ một cụm và các truy vấn khác từ cụm khác:

Sẽ thật tuyệt nếu có một cách để có hai bản sao vật lý của bảng trong đó một bản sao được nhóm một cách và một bản khác được phân cụm nhưng người dùng truy cập vào nó xuất hiện như thể chỉ có 1 bảng và công cụ DB sẽ đảm bảo chúng đang đồng bộ hóa. Rõ ràng là sẽ có hình phạt bằng văn bản khi làm điều này nhưng điều đó không hợp lý cho việc sử dụng của chúng tôi.

Điều gì đó như thế này sẽ có thể?

Tôi đoán không có cách xây dựng để làm những gì tôi mô tả. Để làm điều đó, tôi đoán tôi sẽ tạo một bảng được gọi mytable_dupvới cùng một ràng buộc khóa duy nhất nhưng với phân cụm thay thế và sau đó thiết lập kích hoạt để chèn vào nó bất cứ khi nào chủ được chèn / cập nhật / xóa. Điều đó có vẻ khả thi nhưng từ đây, liệu có một cách hợp lý để selecttừ bảng trùng lặp sẽ hiệu quả?

Tôi đang chạy PostgreSQL 9.4 tại nhà và 9.5 trên Google.


Tôi sẽ thử một chỉ số BRIN trên (vị ngữ).
ypercubeᵀᴹ

Câu trả lời:


5

Để giữ dữ liệu theo hai chuỗi vật lý khác nhau, người ta phải lưu trữ dữ liệu hai lần. Điều này có thể đạt được bằng cách xác định một chỉ số thứ hai, bao gồm. Một chỉ mục bao gồm tất cả các cột được yêu cầu bởi một truy vấn. Bằng cách này, trình tối ưu hóa không cần phải tham khảo bảng cơ sở để đọc các giá trị tiếp theo và không có khả năng quay lại quét bảng cơ sở cho kế hoạch truy vấn. Trình tối ưu hóa thực hiện quét chỉ mục . Vì sự lựa chọn chỉ số được thực hiện bởi trình tối ưu hóa và không phải là lập trình viên, không cần thay đổi mã ứng dụng để tận dụng lợi thế trong quá trình đọc. Không có đối tượng tiếp theo được yêu cầu để duy trì tính nhất quán trong khi viết.

Các cột được sử dụng trong mệnh đề WHERE sẽ là các cột hàng đầu của chỉ mục. Trình tự của các cột khác là không quan trọng. Vì và khi PostgreSQL hỗ trợ cú pháp INCLUDE, chỉ mục này có thể được thay đổi để sử dụng nó.

Nhược điểm bao gồm a) đĩa phụ để lưu trữ dữ liệu này b) độ trễ bổ sung trong quá trình ghi để duy trì chỉ số c) cần bảo trì hệ thống nhiều hơn cho reorgs và như vậy, và d) khi các truy vấn thay đổi chỉ số che phủ phải thay đổi để phù hợp với e ) tương ứng lớn hơn và sao lưu dài hơn và khôi phục.


Có nhiều khả năng đây là một câu trả lời tốt hơn của tôi :)
dezso

3

Bạn có thể tạo ra một cái nhìn cụ thể hóa trên bàn của bạn:

CREATE MATERIALIZED VIEW thecopy AS SELECT * FROM mytable;

Sau đó, thêm một chỉ mục duy nhất phù hợp với PK của bạn trên mytable(bạn không thể thêm PK 'thực' ở đó vì đó không phải là bảng 'thực'):

CREATE UNIQUE INDEX ON thecopy (node_id, pricedate, hour);

Vì vậy, bản sao của bạn là ở đó. Nếu bạn muốn phân cụm nó, bạn cần một chỉ mục cho nó:

CREATE INDEX ON thecopy (pricedate);
CLUSTER thecopy USING thecopy_pricedate_idx;
-- You can also do 
-- ALTER MATERIALIZED VIEW thecopy CLUSTER ON thecopy_pricedate_idx;
-- https://www.postgresql.org/docs/current/static/sql-altermaterializedview.html

Sau đó, bất cứ khi nào bạn cần nó (về cơ bản sau khi tải dữ liệu hàng ngày kết thúc), hãy thực hiện

REFRESH MATERIALIZED VIEW [CONCURRENTLY] thecopy;

Và sau đó thay đổi loại truy vấn thứ hai để đi đến MV thay vì bảng.


Tôi đánh giá cao rằng một khung nhìn cụ thể hóa được sắp xếp hợp lý hơn một bảng có các kích hoạt nhưng mục tiêu chính của tôi là làm cho quá trình chọn được sắp xếp hợp lý.
Dean MacGregor

@DeanMacGregor tốt, nếu không có một bảng riêng biệt, bạn sẽ không có một trật tự vật lý riêng (có vẻ như nó sẽ giúp bạn). Nếu bằng cách hợp lý hóa, bạn có nghĩa là bạn muốn chọn từ một nơi nào đó sau đó sẽ được gửi đi một trong hai bản sao, tôi không biết.
dezso

-1

Vì vậy, giả sử bạn muốn giữ nó đơn giản cho người dùng của mệnh đề chọn và không biết họ đang thực thi nó như thế nào ...

Làm thế nào về việc sử dụng một chức năng?

Một thay thế:

Truyền toàn bộ mệnh đề select dưới dạng (các) tham số cho hàm,

phân tích cú pháp cho cột mệnh đề where

và sau đó hướng nó tới bảng hoặc khung nhìn cụ thể hóa theo đề xuất của @dezso?

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.