2011-11-25 32 views
5

Tôi đang thiết lập cơ sở dữ liệu PostgreSQL 9 mới chứa hàng triệu (hoặc có thể là hàng tỷ) hàng. Vì vậy, tôi quyết định phân vùng dữ liệu bằng cách sử dụng thừa kế PostgreSQL.Chọn đúng quy tắc phân vùng

Tôi tạo ra một bảng tổng thể như thế này (đơn giản hóa ví dụ):

CREATE TABLE mytable 
(
    user_id integer, 
    year integer, 
    CONSTRAINT pk_mytable PRIMARY KEY (user_id, year) 
); 

Và 10 phân vùng bảng:

CREATE TABLE mytable_0() INHERITS (mytable); 
CREATE TABLE mytable_1() INHERITS (mytable); 
... 
CREATE TABLE mytable_9() INHERITS (mytable); 

Tôi biết rằng hàng sẽ luôn luôn được truy cập từ các ứng dụng bằng cách sử dụng độc đáo điều kiện user_id. Vì vậy, tôi muốn truyền dữ liệu "khá" bằng nhau trên 10 bảng bằng cách sử dụng một quy tắc dựa trên user_id.

Để truy vấn điều chỉnh trên bảng tổng thể, ý tưởng đầu tiên của tôi là sử dụng một hạn chế kiểm tra mô đun:

ALTER TABLE mytable_0 ADD CONSTRAINT mytable_user_id_check CHECK (user_id % 10 = 0); 
ALTER TABLE mytable_1 ADD CONSTRAINT mytable_user_id_check CHECK (user_id % 10 = 1); 
... 

Vấn đề là, khi tôi truy vấn bảng tổng thể "mytable" với điều kiện trên user_id, PostgreSQL phân tích rà soát tất cả các bảng và không được hưởng lợi từ ràng buộc kiểm tra:

EXPLAIN SELECT * FROM mytable WHERE user_id = 12345; 

"Result (cost=0.00..152.69 rows=64 width=36)" 
" -> Append (cost=0.00..152.69 rows=64 width=36)" 
"  -> Seq Scan on mytable (cost=0.00..25.38 rows=6 width=36)" 
"    Filter: (user_id = 12345)" 
"  -> Seq Scan on mytable_0 mytable (cost=0.00..1.29 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 
"  -> Seq Scan on mytable_1 mytable (cost=0.00..1.52 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 
... 
"  -> Seq Scan on mytable_9 mytable (cost=0.00..1.52 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 

trong khi đó nếu tôi sử dụng một hạn chế kiểm tra cổ điển như thế này (và các phân vùng lại phù hợp với quy tắc đó):

ALTER TABLE mytable_0 ADD CONSTRAINT mytable_user_id_check CHECK (user_id BETWEEN 1 AND 10000); 
ALTER TABLE mytable_1 ADD CONSTRAINT mytable_user_id_check CHECK (user_id BETWEEN 10001 AND 20000); 
... 

nó sẽ quét chỉ bảng phù hợp với điều kiện (mytable và mytable_1 trong ví dụ này):

"Result (cost=0.00..152.69 rows=64 width=36)" 
" -> Append (cost=0.00..152.69 rows=64 width=36)" 
"  -> Seq Scan on mytable (cost=0.00..25.38 rows=6 width=36)" 
"    Filter: (user_id = 12345)" 
"  -> Seq Scan on mytable_1 mytable (cost=0.00..1.52 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 

Nhưng sử dụng ràng buộc kiểm tra như vậy rất khó để duy trì vì phạm vi của người sử dụng mà sẽ được áp dụng trong các bảng sẽ thay đổi qua các năm. hàng ngàn đầu tiên, có thể là hàng triệu hoặc nhiều hơn trong tương lai gần ...

Quy tắc nào tôi có thể sử dụng để phân vùng dữ liệu của mình trên 10 bảng có thể hưởng lợi từ ràng buộc kiểm tra để SELECT trên bảng chính sẽ chỉ quét cái bàn bên phải ...?

Cảm ơn, Nico

Trả lời

5

Hạn chế là với các nhà quy hoạch chứ không phải là partioning riêng của mình. Nó bao phủ trong cuốn hướng dẫn một cách chi tiết:

http://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

Có hai điều bạn đề cập đến mặc dù cần phải được xem xét.

Thứ nhất, bạn nói rằng tất cả quyền truy cập sẽ thông qua khóa chính. Điều này có nghĩa là bạn sẽ không nhận được lợi ích hiệu suất từ ​​phân vùng (ít nhất là không sử dụng bình thường). Chỉ mục trên mỗi phân vùng sẽ nhỏ hơn, nhưng PG cần phải chọn phân vùng nào để kiểm tra trước. Nơi bạn sẽ đạt được là nếu bạn cần phải reindex hoặc tương tự - bạn có thể reindex từng phân vùng riêng biệt.

Thứ hai, bạn nói rằng bạn có thể có bất kỳ thứ gì từ hàng nghìn đến hàng tỷ hàng. Điều này dẫn tôi đến hai kết luận:

  1. Có thể để lại quyết định sau này. Chờ cho đến khi bạn cần phân vùng.
  2. Bạn không muốn chính xác 10 phân vùng với hai nghìn hàng và hai tỷ.

Nếu bạn định phân vùng, hãy thực hiện theo phạm vi - nói 100.000 hàng hoặc 1 triệu mỗi phân vùng. Thêm một cron-job để kiểm tra ID tối đa được sử dụng và tạo một phân vùng mới nếu cần thiết (một lần một ngày có lẽ).

Cá nhân, tuy nhiên, tôi sẽ để nó cho đến khi tôi cần. Có thể có một phân vùng duy nhất như một bản tóm tắt nếu bạn cho rằng có nhiều khả năng bạn sẽ không cần đến chúng sau này.

1

WHERE cần phải có cùng biểu thức với số CHECK, i. e., người lập kế hoạch truy vấn sẽ không nhận ra rằng user_id = 12345 cho phép kết luận rằng user_id % 10 = 5. Hãy thử

EXPLAIN SELECT * FROM mytable WHERE user_id = 12345 AND user_id % 10 = 5; 

Điều đó nói rằng, tôi muốn thứ hai Richard Huxton's answer trong đó bạn có thể muốn hoãn phân vùng đến khi bạn có thêm thông tin về kích thước của tập dữ liệu, eidea là để tránh tối ưu hóa sớm thứ. Postgres có thể rất nhanh trên các bảng khá lớn, nó sẽ đưa bạn khá xa mà không cần phân vùng.