Postgres: công cụ lập kế hoạch truy vấn không tôn trọng ràng buộc kế thừa bảng khi truy vấn null


7

Tôi gặp sự cố với các truy vấn chậm do trình lập kế hoạch kiểm tra mọi bảng được kế thừa thay vì chỉ có bảng có ràng buộc.

Tôi có một bảng có 0 hàng gọi là "search_result". Bảng này có một vài bảng được kế thừa với các ràng buộc khác nhau dựa trên "phân cực", nơi tất cả dữ liệu của chúng tôi nằm. Ví dụ:

CREATE TABLE search_result_positive
(
  CONSTRAINT search_result_positive_polarization_check CHECK (polarization = (1))
)
INHERITS (search_result);

CREATE TABLE search_result_negative
(
  CONSTRAINT search_result_negative_polarization_check CHECK (polarization = (-1))
)
INHERITS (search_result);

CREATE TABLE search_result_unpolarized
(
  CONSTRAINT search_result_unpolarized_polarization_check CHECK (polarization IS NULL)
)
INHERITS (search_result);

Ví dụ, khi tôi thực hiện truy vấn bằng cách sử dụng "WHERE Polarization = 1", trình lập kế hoạch truy vấn sẽ hiển thị rằng nó chỉ kiểm tra bảng "search_result_poseitive": đây là hành vi mong muốn.

Tuy nhiên, khi truy vấn là "WHERE phân cực là NULL", nó sẽ kiểm tra từng bảng một, mất rất nhiều thời gian. Đây là một ví dụ cho "search_result_poseitive":

SELECT  "search_result".* FROM "search_result"  WHERE (polarization = 1)  ORDER BY published_on DESC LIMIT 20;

Limit  (cost=0.44..17.65 rows=20 width=2027) (actual time=3.638..3.666 rows=20 loops=1)
  ->  Merge Append  (cost=0.44..249453.67 rows=289872 width=2027) (actual time=3.637..3.663 rows=20 loops=1)
        Sort Key: search_result.published_on DESC
        ->  Sort  (cost=0.01..0.02 rows=1 width=2882) (actual time=0.004..0.004 rows=0 loops=1)
              Sort Key: search_result.published_on DESC
              Sort Method: quicksort  Memory: 25kB
              ->  Seq Scan on search_result  (cost=0.00..0.00 rows=1 width=2882) (actual time=0.002..0.002 rows=0 loops=1)
                    Filter: (polarization = 1)
        ->  Index Scan Backward using ix_search_result_positive_published_on_asc on search_result_positive  (cost=0.42..245830.25 rows=289871 width=2027) (actual time=3.633..3.658 rows=20 loops=1)
              Filter: (polarization = 1)
Planning time: 2.640 ms
Execution time: 3.762 ms

Và bây giờ, đây là những gì xảy ra khi chúng tôi truy vấn null:

SELECT  "search_result".* FROM "search_result"  WHERE (polarization IS NULL)  ORDER BY published_on DESC LIMIT 20;

Limit  (cost=1.93..143.83 rows=20 width=1758) (actual time=205790.210..206266.419 rows=20 loops=1)
  ->  Merge Append  (cost=1.93..462744.74 rows=65221 width=1758) (actual time=205790.208..206266.403 rows=20 loops=1)
        Sort Key: search_result.published_on DESC
        ->  Sort  (cost=0.01..0.02 rows=1 width=2882) (actual time=0.006..0.006 rows=0 loops=1)
              Sort Key: search_result.published_on DESC
              Sort Method: quicksort  Memory: 25kB
              ->  Seq Scan on search_result  (cost=0.00..0.00 rows=1 width=2882) (actual time=0.001..0.001 rows=0 loops=1)
                    Filter: (polarization IS NULL)
        ->  Index Scan using ix_search_result_hybrid_published_on_desc on search_result_hybrid  (cost=0.14..44.44 rows=1 width=2882) (actual time=0.002..0.002 rows=0 loops=1)
              Filter: (polarization IS NULL)
        ->  Index Scan Backward using ix_search_result_negative_published_on_asc on search_result_negative  (cost=0.42..126163.49 rows=1 width=2039) (actual time=44646.431..44646.431 rows=0 loops=1)
              Filter: (polarization IS NULL)
              Rows Removed by Filter: 174428
        ->  Index Scan Backward using ix_search_result_neutral_published_on_asc on search_result_neutral  (cost=0.42..53749.59 rows=1 width=1996) (actual time=29539.393..29539.393 rows=0 loops=1)
              Filter: (polarization IS NULL)
              Rows Removed by Filter: 115678
        ->  Index Scan using ix_search_result_no_apply_published_on_desc on search_result_no_apply  (cost=0.14..44.44 rows=1 width=2882) (actual time=0.003..0.003 rows=0 loops=1)
              Filter: (polarization IS NULL)
        ->  Index Scan Backward using ix_search_result_positive_published_on_asc on search_result_positive  (cost=0.42..245105.57 rows=1 width=2027) (actual time=131590.509..131590.509 rows=0 loops=1)
              Filter: (polarization IS NULL)
              Rows Removed by Filter: 295475
        ->  Index Scan using ix_search_result_unpolarized_published_on_desc on search_result_unpolarized  (cost=0.29..35643.06 rows=65215 width=1758) (actual time=13.863..490.048 rows=20 loops=1)
              Filter: (polarization IS NULL)
Planning time: 1.197 ms
Execution time: 206266.593 ms

Điều này khiến tôi điên mất. Tôi không hiểu tại sao mọi bảng đang được kiểm tra thay vì chỉ "search_result_unpolarized". Điều này đang khiến tôi phát điên. Sự lựa chọn duy nhất khác mà tôi có cho việc này là viết lại một phần trong hệ thống của chúng tôi để chỉ truy vấn một bảng cụ thể thay vì để Postgres quyết định, đây sẽ là một lượng công việc khá lớn. Phải có cách tốt hơn. Bất kỳ trợ giúp hay ý tưởng sẽ được đánh giá rất nhiều.

Chúng tôi đang sử dụng Postgres 9.3.19 trên Amazon RDS


Đây có phải là để làm việc trong PG 9.3?
Colin 't Hart

2
Ngoài ra, 9.3 là rất cũ. Rất khuyến nghị nâng cấp lên 10.
Colin 't Hart

Tôi nghĩ rằng đó là một hạn chế của phân vùng dựa trên thừa kế cũ.
a_horse_with_no_name

1
Tôi đồng ý, chúng tôi cần cập nhật. Tôi vừa kiểm tra, chúng tôi có một cơ sở dữ liệu khác nhau với cùng một lược đồ trên 9.6, cùng một vấn đề xảy ra. Tuy nhiên, điều làm tôi bối rối là tại sao nó hoạt động với độ phân cực = 1 nhưng không phân cực là null
MarceloJ

1
Tôi biết là gần 1 năm nhưng PostgreSQL quét tất cả các bảng con vì bạn có giá trị null trên chúng. Bạn cần thêm một hằng số nữa check (polarization is not null)nhưng trước tiên bạn cần di chuyển các giá trị null ra khỏi các bảng con.
Yavuz Selim

Câu trả lời:


1

Loại trừ ràng buộc có một số hãy cẩn thận. Chính trường hợp này (không phải là NULL-ness không được xem xét, ngay cả khi kiểm tra hiện có liên quan đến nó) không được liệt kê trong tài liệu , nhưng nó vẫn còn ở các phiên bản sau. Giải pháp là thêm một kiểm tra khác loại trừ rõ ràng NULL:

ALTER TABLE search_result_positive ADD CHECK (polarization IS NOT NULL);
ALTER TABLE search_result_negative ADD CHECK (polarization IS NOT NULL);
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.