2009-09-23 41 views
9

Có cách nào để tôi buộc phải tham gia một đơn đặt hàng cụ thể trong Postgres không?Thứ tự tham gia bảng trong bưu điện

Tôi có một truy vấn giống như thế này. Tôi đã loại bỏ một loạt các nội dung trong truy vấn thực sự, nhưng sự đơn giản hóa này cho thấy sự cố. Những gì còn lại không nên quá khó hiểu: Sử dụng một vai trò/nhiệm vụ bảo mật hệ thống, tôi đang cố gắng để xác định xem một người dùng nhất định có đặc quyền để thực hiện một nhiệm vụ nhất định.

select task.taskid 
from userlogin 
join userrole using (userloginid) 
join roletask using (roleid) 
join task using (taskid) 
where loginname='foobar' 
and taskfunction='plugh' 

Nhưng tôi nhận ra rằng chương trình đã biết giá trị của UserLogin, vì vậy nó có vẻ các truy vấn có thể được thực hiện hiệu quả hơn bằng cách bỏ qua việc tra cứu trên UserLogin và chỉ cần điền vào userloginid, như thế này:

select task.taskid 
from userrole 
join roletask using (roleid) 
join task using (taskid) 
where userloginid=42 
and taskfunction='plugh' 

Khi tôi làm điều đó - loại bỏ một bảng khỏi truy vấn và mã hóa cứng giá trị được truy xuất từ ​​bảng đó thay thế - thời gian lập kế hoạch giải thích tăng lên! Trong truy vấn ban đầu, Postgres đọc userlogin sau đó userrole sau đó roletask sau đó nhiệm vụ. Nhưng trong truy vấn mới, nó quyết định đọc roletask đầu tiên, và sau đó tham gia vào userrole, mặc dù điều này yêu cầu thực hiện quét toàn bộ tệp trên roletask.

Full giải thích kế hoạch là:

Phiên bản 1:

Hash Join (cost=12.79..140.82 rows=1 width=8) 
    Hash Cond: (roletask.taskid = task.taskid) 
    -> Nested Loop (cost=4.51..129.73 rows=748 width=8) 
     -> Nested Loop (cost=4.51..101.09 rows=12 width=8) 
       -> Index Scan using idx_userlogin_loginname on userlogin (cost=0.00..8.27 rows=1 width=8) 
        Index Cond: ((loginname)::text = 'foobar'::text) 
       -> Bitmap Heap Scan on userrole (cost=4.51..92.41 rows=33 width=16) 
        Recheck Cond: (userrole.userloginid = userlogin.userloginid) 
        -> Bitmap Index Scan on idx_userrole_login (cost=0.00..4.50 rows=33 width=0) 
          Index Cond: (userrole.userloginid = userlogin.userloginid) 
     -> Index Scan using idx_roletask_role on roletask (cost=0.00..1.50 rows=71 width=16) 
       Index Cond: (roletask.roleid = userrole.roleid) 
    -> Hash (cost=8.27..8.27 rows=1 width=8) 
     -> Index Scan using idx_task_taskfunction on task (cost=0.00..8.27 rows=1 width=8) 
       Index Cond: ((taskfunction)::text = 'plugh'::text) 

Version 2:

Hash Join (cost=96.58..192.82 rows=4 width=8) 
    Hash Cond: (roletask.roleid = userrole.roleid) 
    -> Hash Join (cost=8.28..104.10 rows=9 width=16) 
     Hash Cond: (roletask.taskid = task.taskid) 
     -> Seq Scan on roletask (cost=0.00..78.35 rows=4635 width=16) 
     -> Hash (cost=8.27..8.27 rows=1 width=8) 
       -> Index Scan using idx_task_taskfunction on task (cost=0.00..8.27 rows=1 width=8) 
        Index Cond: ((taskfunction)::text = 'plugh'::text) 
    -> Hash (cost=87.92..87.92 rows=31 width=8) 
     -> Bitmap Heap Scan on userrole (cost=4.49..87.92 rows=31 width=8) 
       Recheck Cond: (userloginid = 42) 
       -> Bitmap Index Scan on idx_userrole_login (cost=0.00..4.49 rows=31 width=0) 
        Index Cond: (userloginid = 42) 

(Vâng, tôi biết rằng trong cả hai trường hợp, chi phí thấp và sự khác biệt doesn Nhưng đây là sau khi tôi loại bỏ một loạt các công việc bổ sung từ truy vấn để đơn giản hóa những gì tôi phải đăng. Truy vấn thực sự vẫn không phải là thái quá, nhưng tôi quan tâm nhiều hơn đến t . Ông nguyên tắc)

+2

Bạn có thể hiển thị kế hoạch truy vấn (giải thích phân tích) và định nghĩa bảng không? – hgmnz

+0

Được rồi, bạn đã hỏi, tôi đã thay thế ví dụ đơn giản giả định bằng truy vấn thực và thêm kết quả kế hoạch giải thích. Ồ, tôi chắc chắn rằng tôi có thể thêm một số chỉ mục bổ sung để tăng tốc truy vấn thứ hai, nhưng đó không phải là vấn đề. Tại sao Postgres lại chọn một kế hoạch ít hơn mức tốt nhất mà nó có thể làm, với các truy vấn mà nó có? Đặc biệt là khi nó chứng minh rằng nó có thể làm tốt hơn nếu tôi làm cho truy vấn phức tạp hơn? – Jay

+0

bạn có so sánh thời gian chạy thực tế của các truy vấn hoặc chỉ xem chi phí tiêu đề trong kế hoạch giải thích không? chi phí? đáng chú ý là bạn vừa đăng đầu ra giải thích, chứ không giải thích phân tích. mặc dù bạn mong đợi chi phí cao hơn để tương đương với một truy vấn chạy chậm hơn, nó có thể không hoạt động theo cách đó. – araqnid

Trả lời

4

trang trong tài liệu này mô tả làm thế nào để ngăn chặn sự ưu PostgreSQL từ sắp xếp lại bảng gia nhập, cho phép bạn kiểm soát thứ tự của gia nhập bản thân:

http://www.postgresql.org/docs/current/interactive/explicit-joins.html

+1

PostgreSQL thực sự có tài liệu tốt nhất mà tôi đã nhìn thấy của một RDBMS. – hgmnz

+1

Bạn đã thử cái này chưa? Tôi chắc chắn không muốn thay đổi cài đặt này cho tất cả các truy vấn, chỉ cho một hoặc hai ở đây và ở đó. Nếu tôi thay đổi nó bằng một câu lệnh đã đặt, điều đó có ảnh hưởng đến toàn bộ cơ sở dữ liệu hay chỉ kết nối hiện tại hoặc giao dịch hiện tại không? Hmm, tôi cho rằng tôi có thể kiểm tra điều này bằng cách mở hai kết nối, thiết lập nó từ một, và sau đó nhìn thấy nếu giải thích kế hoạch về sự thay đổi khác ... – Jay

+0

Tôi đã không thử nó. Bạn nói đúng khi thử nó trong một cặp phiên đồng thời là cách tốt nhất để chắc chắn. Doc có thể sai (mặc dù như @hgiminez chỉ ra, hiếm khi trong tài liệu của PostgreSQL). –

1

Bạn có chắc chắn bảng thống kê của bạn được cập nhật? Khi PostgreSQLs tối ưu hóa chi phí dựa trên thất bại với những điều tầm thường như vậy đó là một dấu hiệu khá tốt một cái gì đó là nghiêm trọng sai với bảng thống kê. Nó là tốt hơn để sửa chữa nguyên nhân gốc rễ hơn để làm việc xung quanh nó bằng cách ghi đè xây dựng trong tối ưu hóa bởi vì vấn đề chắc chắn sẽ bật lên ở một nơi khác là tốt.

Chạy ANALYZE trên các bảng bị ảnh hưởng và xem liệu nó có làm cho PostgreSQL chọn gói khác không. Nếu nó vẫn chọn một cái gì đó ngớ ngẩn nó sẽ thực sự thú vị để xem các kế hoạch truy vấn. Trình tối ưu hóa không làm đúng thứ thường được coi là lỗi.

+0

Có. Sau kết quả đáng ngạc nhiên ban đầu của tôi, tôi đã chạy lại phân tích trên các bảng đó và sau đó làm lại các kế hoạch giải thích, và kết quả tương tự. – Jay

+1

Điều đó có vẻ hơi lạ. Cài đặt effective_cache_size của bạn là gì? 128M mặc định có thể dẫn đến quét tuần tự không hợp lý trên các bảng vừa và nhỏ. Ngoài ra, đối với các cơ sở dữ liệu được lưu trữ rất nhiều, việc giảm random_page_cost có thể là một ý tưởng hay. –

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