2013-04-10 7 views
6

2013-05-29: Đã cập nhật câu hỏi với cấu hình mới nhất và thông tin bổ sung. Trước đó tôi đã thử nghiệm trong một hình ảnh virtualbox. Bây giờ tôi đang thử nghiệm trên máy chủ sản xuất, phản ánh thế giới thực tốt hơn nhiều. Bây giờ câu hỏi phải hoàn toàn rõ ràng. Nếu bạn đã giúp tôi trước, hãy đọc kỹ một cách cẩn thậnPostgreSQL Chọn câu lệnh rất chậm do bộ lọc JOIN/WHERE nhỏ

Hiện tại tôi đã tìm thấy một truy vấn rất chậm trong PostgreSQL, mặc dù tôi không hiểu nó có thể chậm như thế nào. Tôi thu nhỏ nó xuống một chút vì vậy nó nhỏ hơn nhiều để đăng ở đây (và nhanh hơn nhiều, nhưng vẫn còn chậm!).

Nền tảng nhỏ: Trong dự án này, tôi có quảng cáo thuộc về người dùng. Người dùng là một phần của một khu vực trong quốc gia. Một khu vực có thể có nhiều khu vực con, vì vậy bảng khu vực là một cây. Mạng được gán cho một khu vực. Khi lọc trên mạng, nó sẽ lọc trên vùng đó và tất cả các vùng con của nó trong cây. Bởi vì tôi không thể truy vấn một cây bất tận, tôi có cái bàn làm phẳng cây đầy đủ này.

Vì vậy, với 1 truy vấn (SELECT area_id FROM network_area_flatdeep WHERE network_id = 1) tôi nhận được tất cả các khu vực thuộc về mạng 1: 63, 64, 65, 66, 67, 68, 69, 70

Điều này làm cho truy vấn rất dễ dàng.

Các truy vấn chậm (Trước khi kiểm tra tất cả mọi thứ đã được phân tích CHÂN KHÔNG):

EXPLAIN ANALYZE SELECT a0_.id AS id0 
FROM advert a0_ 
     INNER JOIN member m6_ 
       ON a0_.user_id = m6_.id 
     INNER JOIN area a7_ 
       ON m6_.area_id = a7_.id 
WHERE a0_.status IN (1) 
     AND m6_.status IN (1) 
     AND a7_.id IN (SELECT area_id FROM network_area_flatdeep WHERE network_id IN (1)) 
ORDER BY a0_.created_date DESC 
LIMIT 60; 
                       QUERY PLAN                     
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=41.10..34695.53 rows=60 width=12) (actual time=9.327..134.581 rows=60 loops=1) 
    -> Nested Loop (cost=41.10..2291276.69 rows=3967 width=12) (actual time=9.326..134.534 rows=60 loops=1) 
     Join Filter: (a7_.id = m6_.area_id) 
     Rows Removed by Join Filter: 22566 
     -> Nested Loop (cost=41.10..821630.16 rows=317633 width=24) (actual time=0.049..39.638 rows=22666 loops=1) 
       -> Index Scan Backward using advert_created_date_idx on advert a0_ (cost=0.00..762000.64 rows=317633 width=16) (actual time=0.013..4.357 rows=2834 loops=1) 
        Filter: (status = 1) 
        Rows Removed by Filter: 21 
       -> Materialize (cost=41.10..73.38 rows=15 width=8) (actual time=0.000..0.004 rows=8 loops=2834) 
        -> Nested Loop (cost=41.10..73.30 rows=15 width=8) (actual time=0.031..0.073 rows=8 loops=1) 
          -> HashAggregate (cost=41.10..41.18 rows=8 width=4) (actual time=0.023..0.026 rows=8 loops=1) 
           -> Bitmap Heap Scan on network_area_flatdeep (cost=4.37..41.06 rows=15 width=4) (actual time=0.011..0.015 rows=8 loops=1) 
             Recheck Cond: (network_id = 1) 
             -> Bitmap Index Scan on idx_c29e880034128b91 (cost=0.00..4.36 rows=15 width=0) (actual time=0.007..0.007 rows=8 loops=1) 
              Index Cond: (network_id = 1) 
          -> Index Only Scan using area_pkey on area a7_ (cost=0.00..4.01 rows=1 width=4) (actual time=0.002..0.003 rows=1 loops=8) 
           Index Cond: (id = network_area_flatdeep.area_id) 
           Heap Fetches: 8 
     -> Index Scan using member_pkey on member m6_ (cost=0.00..4.61 rows=1 width=8) (actual time=0.002..0.003 rows=1 loops=22666) 
       Index Cond: (id = a0_.user_id) 
       Filter: (status = 1) 
       Rows Removed by Filter: 0 
Total runtime: 134.698 ms 
(23 rows) 

Các subquery chính nó là:

EXPLAIN ANALYZE SELECT area_id FROM network_area_flatdeep WHERE network_id IN (1); 
                 QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on network_area_flatdeep (cost=4.37..41.06 rows=15 width=4) (actual time=0.020..0.024 rows=8 loops=1) 
    Recheck Cond: (network_id = 1) 
    -> Bitmap Index Scan on idx_c29e880034128b91 (cost=0.00..4.36 rows=15 width=0) (actual time=0.012..0.012 rows=8 loops=1) 
     Index Cond: (network_id = 1) 
Total runtime: 0.051 ms 
(5 rows) 

mà kết quả trong: 63, 64, 65, 66, 67, 68, 69, 70

Vì vậy, tôi đã cố gắng để mã cứng trong các id. Và dự kiến ​​nó sẽ được nhanh hơn (nhưng không phải là):

EXPLAIN ANALYZE SELECT a0_.id AS id0 
FROM advert a0_ 
     INNER JOIN member m6_ 
       ON a0_.user_id = m6_.id 
     INNER JOIN area a7_ 
        ON m6_.area_id = a7_.id 
WHERE a0_.status IN (1) 
     AND m6_.status IN (1) 
     AND a7_.id IN (63, 64, 65, 66, 67, 68, 69, 70) 
ORDER BY a0_.created_date DESC 
LIMIT 60; 
                      QUERY PLAN                   
---------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=17558.82..17558.97 rows=60 width=12) (actual time=56.594..56.670 rows=60 loops=1) 
    -> Sort (cost=17558.82..17560.07 rows=498 width=12) (actual time=56.593..56.621 rows=60 loops=1) 
     Sort Key: a0_.created_date 
     Sort Method: top-N heapsort Memory: 27kB 
     -> Nested Loop (cost=0.00..17541.62 rows=498 width=12) (actual time=0.047..53.808 rows=4478 loops=1) 
       -> Nested Loop (cost=0.00..3903.99 rows=286 width=4) (actual time=0.027..17.492 rows=8004 loops=1) 
        -> Seq Scan on area a7_ (cost=0.00..144.78 rows=8 width=4) (actual time=0.007..0.823 rows=8 loops=1) 
          Filter: (id = ANY ('{63,64,65,66,67,68,69,70}'::integer[])) 
          Rows Removed by Filter: 5081 
        -> Index Scan using idx_70e4fa78bd0f409c on member m6_ (cost=0.00..468.38 rows=152 width=8) (actual time=0.011..1.208 rows=1000 loops=8) 
          Index Cond: (area_id = a7_.id) 
          Filter: (status = 1) 
          Rows Removed by Filter: 2 
       -> Index Scan using idx_54f1f40ba76ed395 on advert a0_ (cost=0.00..47.49 rows=19 width=16) (actual time=0.002..0.003 rows=1 loops=8004) 
        Index Cond: (user_id = m6_.id) 
        Filter: (status = 1) 
        Rows Removed by Filter: 1 
Total runtime: 56.744 ms 
(18 rows) 

Time: 57.995 ms 

Tôi cố gắng để đưa các subquery trong INNER JOIN:

EXPLAIN ANALYZE SELECT a0_.id AS id0 
FROM advert a0_ 
     INNER JOIN member m6_ 
       ON a0_.user_id = m6_.id 
     INNER JOIN area a7_ 
       ON m6_.area_id = a7_.id 
       AND m6_.area_id IN (SELECT area_id FROM network_area_flatdeep WHERE network_id IN  (1)) 
WHERE a0_.status IN (1) 
     AND m6_.status IN (1) 
ORDER BY a0_.created_date DESC 
LIMIT 60; 
                       QUERY PLAN                      
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=4.37..34966.73 rows=60 width=12) (actual time=2.957..42.443 rows=60 loops=1) 
    -> Nested Loop (cost=4.37..2311599.10 rows=3967 width=12) (actual time=2.956..42.394 rows=60 loops=1) 
     -> Nested Loop Semi Join (cost=4.37..2302173.51 rows=3967 width=20) (actual time=2.949..42.099 rows=60 loops=1) 
       Join Filter: (m6_.area_id = network_area_flatdeep.area_id) 
       Rows Removed by Join Filter: 22333 
       -> Nested Loop (cost=0.00..2230853.09 rows=316797 width=16) (actual time=0.028..18.612 rows=2829 loops=1) 
        -> Index Scan Backward using advert_created_date_idx on advert a0_ (cost=0.00..762000.64 rows=317633 width=16) (actual time=0.012..3.802 rows=2834 loops=1) 
          Filter: (status = 1) 
          Rows Removed by Filter: 21 
        -> Index Scan using member_pkey on member m6_ (cost=0.00..4.61 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=2834) 
          Index Cond: (id = a0_.user_id) 
          Filter: (status = 1) 
          Rows Removed by Filter: 0 
       -> Materialize (cost=4.37..41.14 rows=15 width=4) (actual time=0.000..0.004 rows=8 loops=2829) 
        -> Bitmap Heap Scan on network_area_flatdeep (cost=4.37..41.06 rows=15 width=4) (actual time=0.009..0.015 rows=8 loops=1) 
          Recheck Cond: (network_id = 1) 
          -> Bitmap Index Scan on idx_c29e880034128b91 (cost=0.00..4.36 rows=15 width=0) (actual time=0.006..0.006 rows=8 loops=1) 
           Index Cond: (network_id = 1) 
     -> Index Only Scan using area_pkey on area a7_ (cost=0.00..2.37 rows=1 width=4) (actual time=0.002..0.003 rows=1 loops=60) 
       Index Cond: (id = m6_.area_id) 
       Heap Fetches: 60 
Total runtime: 42.538 ms 
(22 rows) 

tôi đã cố gắng để thoát khỏi subquery và thực hiện một hợp THAM GIA tuyên bố network_area_flatdeep (tôi MẠNH thích phiên bản này):

EXPLAIN ANALYZE SELECT a0_.id AS id0 
FROM advert a0_ 
     INNER JOIN member m6_ 
       ON a0_.user_id = m6_.id 
     INNER JOIN area a7_ 
       ON m6_.area_id = a7_.id 
     INNER JOIN network_area_flatdeep n14_ 
       ON a7_.id = n14_.area_id 
        AND (n14_.network_id IN (1)) 
WHERE a0_.status IN (1) 
     AND m6_.status IN (1) 
ORDER BY a0_.created_date DESC 
LIMIT 60; 
                        QUERY PLAN                      
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=30031.18..30031.33 rows=60 width=12) (actual time=62.968..63.045 rows=60 loops=1) 
    -> Sort (cost=30031.18..30033.51 rows=934 width=12) (actual time=62.967..62.991 rows=60 loops=1) 
     Sort Key: a0_.created_date 
     Sort Method: top-N heapsort Memory: 27kB 
     -> Nested Loop (cost=0.00..29998.92 rows=934 width=12) (actual time=0.157..60.280 rows=4478 loops=1) 
       -> Nested Loop (cost=0.00..4401.66 rows=536 width=4) (actual time=0.029..20.488 rows=8004 loops=1) 
        -> Nested Loop (cost=0.00..120.69 rows=15 width=8) (actual time=0.015..0.084 rows=8 loops=1) 
          -> Index Scan using idx_c29e880034128b91 on network_area_flatdeep n14_ (cost=0.00..60.47 rows=15 width=4) (actual time=0.009..0.019 rows=8 loops=1) 
           Index Cond: (network_id = 1) 
          -> Index Only Scan using area_pkey on area a7_ (cost=0.00..4.01 rows=1 width=4) (actual time=0.004..0.005 rows=1 loops=8) 
           Index Cond: (id = n14_.area_id) 
           Heap Fetches: 8 
        -> Index Scan using idx_70e4fa78bd0f409c on member m6_ (cost=0.00..283.88 rows=152 width=8) (actual time=0.011..1.278 rows=1000 loops=8) 
          Index Cond: (area_id = a7_.id) 
          Filter: (status = 1) 
          Rows Removed by Filter: 2 
       -> Index Scan using idx_54f1f40ba76ed395 on advert a0_ (cost=0.00..47.57 rows=19 width=16) (actual time=0.003..0.003 rows=1 loops=8004) 
        Index Cond: (user_id = m6_.id) 
        Filter: (status = 1) 
        Rows Removed by Filter: 1 
Total runtime: 63.125 ms 
(21 rows) 

Thay đổi IN-= không helper một trong hai.

Tôi đã thử sử dụng EXISTS như được đề xuất bởi wilderplasser với câu trả lời bên dưới.

Khi tôi xóa tiêu chí ORDER BY hoặc tiêu chí mạng, truy vấn nhanh (2ms). Nhưng tại sao họ không thể chơi tốt với nhau?

Bây giờ thì ... khi tôi thay đổi network_id từ '1' thành '10'. Truy vấn cực nhanh như tôi muốn. 10 là mạng gốc chứa TẤT CẢ các vùng. Vì vậy, một cách hiệu quả các kết quả LESS JOIN cần lọc ra, truy vấn nhanh hơn.

Cấu trúc trông như thế này:

area (mapped to network 10 which contains 5089 areas in flat table and is FAST) 
| |---- area 1 (network 1 which contains 8 areas in flat table and is SLOW) 
|  |--- more areas 
|-- ALOT MORE areas 
|-- etc 

Thay đổi mạng 1-10 cho: 3.265 ms

Để tóm tắt sự khác biệt:

mạng 1 có 8 khu vực trong network_area_flatdeep mạng 10 có 5089 khu vực trong network_area_flatdeep

Vì vậy INNER JOIN sử dụng mạng 1 là rất chậm, INNER JOIN sử dụng mạng 10 được rất nhanh. Hành vi tương tự với truy vấn phụ.

bảng Advert

353804 rows 
                    Table "public.advert" 
      Column   |    Type    |      Modifiers      | Storage | Stats target | Description 
-----------------------------+--------------------------------+-----------------------------------------------------+----------+--------------+------------- 
id       | integer      | not null default nextval('advert_id_seq'::regclass) | plain |    | 
user_id      | integer      | not null           | plain |    | 
advert_category_id   | integer      | not null           | plain |    | 
currency_id     | integer      | not null           | plain |    | 
advert_kind_id    | integer      | not null           | plain |    | 
advert_price_id    | integer      |              | plain |    | 
external_source_id   | integer      |              | plain |    | 
status      | integer      | not null           | plain |    | 
type      | integer      | not null           | plain |    | 
title      | character varying(60)   | not null           | extended |    | 
description     | text       | not null           | extended |    | 
price      | numeric(19,2)     | default NULL::numeric        | main  |    | 
accepting_bids    | boolean      | not null           | plain |    | 
promoted     | boolean      | not null           | plain |    | 
edited_date     | timestamp(0) without time zone | default NULL::timestamp without time zone   | plain |    | 
created_date    | timestamp(0) without time zone | not null           | plain |    | 
archived_date    | timestamp(0) without time zone | default NULL::timestamp without time zone   | plain |    | 
views      | integer      | not null           | plain |    | 
checked_date    | timestamp(0) without time zone | default NULL::timestamp without time zone   | plain |    | 
archived_by_cron   | boolean      | not null           | plain |    | 
unarchived_by_cron   | boolean      | not null           | plain |    | 
containting_forbidden_words | boolean      | not null           | plain |    | 
external_id     | character varying(255)   | default NULL::character varying      | extended |    | 
new_product     | boolean      | not null           | plain |    | 
Indexes: 
    "advert_pkey" PRIMARY KEY, btree (id) 
    "advert_external_idx_uq" UNIQUE, btree (external_id, external_source_id) 
    "advert_archived_date_idx" btree (archived_date) 
    "advert_checked_date_idx" btree (checked_date) 
    "advert_created_date_idx" btree (created_date) 
    "advert_edited_date_idx" btree (edited_date) 
    "advert_external_id_idx" btree (external_id) 
    "advert_price_idx" btree (price) 
    "advert_status_idx" btree (status) 
    "advert_type_idx" btree (type) 
    "advert_views_idx" btree (views) 
    "idx_54f1f40b38248176" btree (currency_id) 
    "idx_54f1f40b54b67d66" btree (advert_price_id) 
    "idx_54f1f40b9a2e6cff" btree (advert_kind_id) 
    "idx_54f1f40ba76ed395" btree (user_id) 
    "idx_54f1f40bb167b375" btree (external_source_id) 
    "idx_54f1f40bd4436821" btree (advert_category_id) 
Foreign-key constraints: 
    "fk_54f1f40b38248176" FOREIGN KEY (currency_id) REFERENCES currency(id) ON DELETE RESTRICT 
    "fk_54f1f40b54b67d66" FOREIGN KEY (advert_price_id) REFERENCES advertprice(id) ON DELETE RESTRICT 
    "fk_54f1f40b9a2e6cff" FOREIGN KEY (advert_kind_id) REFERENCES advertkind(id) ON DELETE RESTRICT 
    "fk_54f1f40ba76ed395" FOREIGN KEY (user_id) REFERENCES member(id) ON DELETE CASCADE 
    "fk_54f1f40bb167b375" FOREIGN KEY (external_source_id) REFERENCES externalsource(id) ON DELETE RESTRICT 
    "fk_54f1f40bd4436821" FOREIGN KEY (advert_category_id) REFERENCES advertcategory(id) ON DELETE RESTRICT 
Referenced by: 
    TABLE "advert_photo" CONSTRAINT "fk_1c939974d07eccb6" FOREIGN KEY (advert_id) REFERENCES advert(id) ON DELETE CASCADE 
    TABLE "banner" CONSTRAINT "fk_6f9db8e7d07eccb6" FOREIGN KEY (advert_id) REFERENCES advert(id) ON DELETE SET NULL 
    TABLE "advertbid" CONSTRAINT "fk_fccdba75d07eccb6" FOREIGN KEY (advert_id) REFERENCES advert(id) ON DELETE CASCADE 
Has OIDs: no 

Diện tích bảng:

5089 rows 
               Table "public.area" 
    Column | Type |      Modifiers      | Storage | Stats target | Description 
------------+---------+---------------------------------------------------+---------+--------------+------------- 
id   | integer | not null default nextval('area_id_seq'::regclass) | plain |    | 
network_id | integer |             | plain |    | 
parent_id | integer |             | plain |    | 
selectable | boolean | not null           | plain |    | 
Indexes: 
    "area_pkey" PRIMARY KEY, btree (id) 
    "idx_d7943d6834128b91" btree (network_id) 
    "idx_d7943d68727aca70" btree (parent_id) 
Foreign-key constraints: 
    "fk_d7943d6834128b91" FOREIGN KEY (network_id) REFERENCES network(id) ON DELETE RESTRICT 
    "fk_d7943d68727aca70" FOREIGN KEY (parent_id) REFERENCES area(id) ON DELETE CASCADE 
Referenced by: 
    TABLE "network_area_flat" CONSTRAINT "fk_10aae5b2bd0f409c" FOREIGN KEY (area_id) REFERENCES area(id) ON DELETE CASCADE 
    TABLE "area_language" CONSTRAINT "fk_17d42f7dbd0f409c" FOREIGN KEY (area_id) REFERENCES area(id) ON DELETE CASCADE 
    TABLE "area_zip_code" CONSTRAINT "fk_62a3bf90bd0f409c" FOREIGN KEY (area_id) REFERENCES area(id) ON DELETE CASCADE 
    TABLE "member" CONSTRAINT "fk_70e4fa78bd0f409c" FOREIGN KEY (area_id) REFERENCES area(id) ON DELETE RESTRICT 
    TABLE "network_area_flatdeep" CONSTRAINT "fk_c29e8800bd0f409c" FOREIGN KEY (area_id) REFERENCES area(id) ON DELETE CASCADE 
    TABLE "area" CONSTRAINT "fk_d7943d68727aca70" FOREIGN KEY (parent_id) REFERENCES area(id) ON DELETE CASCADE 
Has OIDs: no 

Member bảng:

182450 rows 
                   Table "public.member" 
     Column   |    Type    |      Modifiers      | Storage | Stats target | Description 
-----------------------+--------------------------------+-----------------------------------------------------+----------+--------------+------------- 
id     | integer      | not null default nextval('member_id_seq'::regclass) | plain |    | 
language_id   | integer      | not null           | plain |    | 
area_id    | integer      | not null           | plain |    | 
company_id   | integer      |              | plain |    | 
external_source_id | integer      |              | plain |    | 
email     | character varying(255)   | not null           | extended |    | 
password    | character varying(40)   | not null           | extended |    | 
status    | integer      | not null           | plain |    | 
name     | character varying(150)   | not null           | extended |    | 
zip_code    | character varying(20)   |              | extended |    | 
phone_number   | character varying(120)   | default NULL::character varying      | extended |    | 
using_email_service | boolean      | not null           | plain |    | 
edited_date   | timestamp(0) without time zone | default NULL::timestamp without time zone   | plain |    | 
created_date   | timestamp(0) without time zone | not null           | plain |    | 
hiding_on_own_network | boolean      | not null           | plain |    | 
staff     | boolean      | not null           | plain |    | 
superuser    | boolean      | not null           | plain |    | 
external_id   | character varying(255)   | default NULL::character varying      | extended |    | 
last_login_date  | timestamp(0) without time zone | default NULL::timestamp without time zone   | plain |    | 
deleted_adverts  | integer      | not null           | plain |    | 
Indexes: 
    "member_pkey" PRIMARY KEY, btree (id) 
    "user_email_idx_uq" UNIQUE, btree (email) 
    "user_external_idx_uq" UNIQUE, btree (external_id, external_source_id) 
    "idx_70e4fa7882f1baf4" btree (language_id) 
    "idx_70e4fa78979b1ad6" btree (company_id) 
    "idx_70e4fa78b167b375" btree (external_source_id) 
    "idx_70e4fa78bd0f409c" btree (area_id) 
    "user_external_id_idx" btree (external_id) 
    "user_name_idx" btree (name) 
    "user_status_idx" btree (status) 
Foreign-key constraints: 
    "fk_70e4fa7882f1baf4" FOREIGN KEY (language_id) REFERENCES language(id) ON DELETE RESTRICT 
    "fk_70e4fa78979b1ad6" FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE SET NULL 
    "fk_70e4fa78b167b375" FOREIGN KEY (external_source_id) REFERENCES externalsource(id) ON DELETE RESTRICT 
    "fk_70e4fa78bd0f409c" FOREIGN KEY (area_id) REFERENCES area(id) ON DELETE RESTRICT 
Referenced by: 
    TABLE "user_link" CONSTRAINT "fk_4c2dd538a76ed395" FOREIGN KEY (user_id) REFERENCES member(id) ON DELETE CASCADE 
    TABLE "advert" CONSTRAINT "fk_54f1f40ba76ed395" FOREIGN KEY (user_id) REFERENCES member(id) ON DELETE CASCADE 
    TABLE "banner" CONSTRAINT "fk_6f9db8e7a76ed395" FOREIGN KEY (user_id) REFERENCES member(id) ON DELETE SET NULL 
    TABLE "user_admin_module_permission" CONSTRAINT "fk_74fee7cea76ed395" FOREIGN KEY (user_id) REFERENCES member(id) ON DELETE CASCADE 
    TABLE "user_admin_resource_permission" CONSTRAINT "fk_c9fcf279a76ed395" FOREIGN KEY (user_id) REFERENCES member(id) ON DELETE CASCADE 
Has OIDs: no 

Network_area_flatdeep bảng:

10177 rows 
                  Table "public.network_area_flatdeep" 
    Column |    Type    |        Modifiers        | Storage | Stats target | Description 
--------------+--------------------------------+--------------------------------------------------------------------+---------+--------------+------------- 
id   | integer      | not null default nextval('network_area_flatdeep_id_seq'::regclass) | plain |    | 
network_id | integer      | not null               | plain |    | 
area_id  | integer      | not null               | plain |    | 
created_date | timestamp(0) without time zone | not null               | plain |    | 
Indexes: 
    "network_area_flatdeep_pkey" PRIMARY KEY, btree (id) 
    "area_flatdeep_idx_uq" UNIQUE, btree (area_id, network_id, created_date) 
    "idx_c29e880034128b91" btree (network_id) 
    "idx_c29e8800bd0f409c" btree (area_id) 
Foreign-key constraints: 
    "fk_c29e880034128b91" FOREIGN KEY (network_id) REFERENCES network(id) ON DELETE CASCADE 
    "fk_c29e8800bd0f409c" FOREIGN KEY (area_id) REFERENCES area(id) ON DELETE CASCADE 
Has OIDs: no 

máy chủ Ngắn config:

            version              
-------------------------------------------------------------------------------------------------------------- 
PostgreSQL 9.2.4 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3), 64-bit 

      name   | current_setting |  source   
----------------------------+--------------------+---------------------- 
shared_buffers    | 1800MB    | configuration file 
work_mem     | 4MB    | configuration file 

Kết luận:

càng dữ liệu (ít được lọc ra), nhanh hơn truy vấn là. Bây giờ tôi không biết chút nào. PostgreSQL có thể chậm như thế nào? Một lần nữa: 40ms trông không quá chậm, nhưng với truy vấn thực sự với một câu lệnh SELECT lớn, các truy vấn là 1,5 phần lớn thời gian và có thể mất đến 3 giây.

Tất cả lọc được thực hiện trên các chỉ mục. Việc đặt hàng được thực hiện trên một chỉ số quá.

Có ai có ý tưởng làm thế nào để cải thiện bộ lọc đơn giản này tôi rõ ràng cần phải tách dữ liệu?

+1

1) CHÂN KHÔNG PHÂN TÍCH 2) GIẢI THÍCH phân tích (thay vì giải thích) 3) định nghĩa bảng (bao gồm chỉ số) 4) cấu hình (** ít nhất ** {work_mem, effective_cache_size, random_page_cost}) – wildplasser

+1

** Bạn cần để hiển thị cho chúng tôi định nghĩa bảng và chỉ mục. ** Chẩn đoán truy vấn chậm yêu cầu định nghĩa bảng và chỉ mục đầy đủ, không chỉ mô tả hoặc diễn giải. Có thể các bảng của bạn được xác định kém. Có thể các chỉ mục không được tạo chính xác. Có lẽ bạn không có chỉ mục trên cột mà bạn nghĩ bạn đã làm. Không nhìn thấy các định nghĩa bảng và chỉ mục, chúng ta không thể biết được. Nếu bạn biết cách thực hiện 'EXPLAIN' hoặc có kế hoạch thực hiện, hãy đặt kết quả vào câu hỏi. –

+0

1) Tôi đã phân tích chân không. Không khác nhau. 2) Đã thêm vào bài 3) Đã thêm vào bài 4) Tất cả nhận xét trong cấu hình. Đoán nó đang sử dụng các giá trị mặc định? – mauserrifle

Trả lời

1

Bạn sẽ nhận được loại kế hoạch gì khi loại bỏ khu vực không cần thiết (và do đó làm sao lãng) trên khu vực?

SELECT a0_.id AS id0 
FROM advert a0_ 
     INNER JOIN member m6_ 
       ON a0_.user_id = m6_.id 
WHERE a0_.status IN (1) 
     AND m6_.status IN (1) 
     AND m6_.area_id IN (SELECT area_id FROM network_area_flatdeep WHERE network_id IN (1)) 
ORDER BY a0_.created_date DESC 
LIMIT 60; 
+0

Đó là nhanh hơn nhưng không đủ nhanh Tôi đã kết thúc với biến thể này: 'AND (a7_.id IN (SELECT a18_.id FROM network_area_flatdeep n19_ INNER JOIN area a18_ ON n19_.area_id = a18_.id WHERE n19_.network_id IN (?) AND n19_.area_id = a7_.id))' Tại sao? Chỉ cần dùng thử và lỗi. Tôi đã thử tất cả các kết hợp. Bằng cách nào đó điều này làm cho truy vấn sản xuất của tôi (lớn hơn) từ 2s đến dưới 0.1s:/Ngay cả khi tôi thay đổi nó thành EXISTS nó là 2s một lần nữa! Trong một số trường hợp, nó chậm hơn với các tiêu chí khác. Trong trường hợp đó tôi sử dụng phiên bản JOIN. Vì vậy, ứng dụng của tôi có một câu lệnh IF để xây dựng truy vấn cho hiệu suất tối ưu.Không lý tưởng: (nhưng nó hoạt động – mauserrifle

+0

Tôi sẽ tinh chỉnh nhiều hơn trước khi tôi chấp nhận bất kỳ câu trả lời nào. Cảm ơn đề xuất của bạn ở đây cũng vậy. Các thay đổi bạn đã đề xuất về câu hỏi khác của tôi @ http://stackoverflow.com/questions/16815561/slow-or- statement-in-postgresql đã giúp tôi rất nhiều trên truy vấn này (bộ lọc trên PK của quan hệ) – mauserrifle

+0

Đã làm một số tinh chỉnh trong ứng dụng của tôi để quyết định có nên sử dụng JOINS hay Subquery. Cả hai đều thực hiện trong một số tình huống tốt hơn. sửa đổi thực hiện tốt hơn so với bạn đề nghị truy vấn.Nó chỉ cho tôi vào đúng hướng.Cảm ơn bạn cho điều đó! – mauserrifle

2

Cố gắng thay thế các IN(subquery) bởi tương ứng EXISTS(correlated subquery)

SELECT a0_.id AS id0 
FROM advert a0_ 
INNER JOIN member m6_ 
       ON a0_.user_id = m6_.id 
INNER JOIN area a7_ 
       ON m6_.area_id = a7_.id 
WHERE a0_.status IN (1) 
AND m6_.status IN (1) 
AND EXISTS (
    SELECT* 
    FROM network_area_flatdeep xx 
    WHERE xx.area_id = m6_.area_id 
    AND xx.network_id IN (2) 
    ) 
ORDER BY a0_.created_date DESC 
LIMIT 60 
    ; 

Một bạn không cần chìa khóa chính khóa học và các phím nước ngoài relavant. Tôi don'rt biết về network_area_flatdeep.area_id, nếu nó không phải là một PK hoặc FK, bạn có thể cần một chỉ mục trên nó (hoặc làm cho nó một phần của PK composite)

UPDATE: một thử nghiệm với các dữ liệu tổng hợp:

DROP SCHEMA tmp CASCADE; 
CREATE SCHEMA tmp ; 
SET search_path=tmp; 

CREATE Table area 
(id SERIAL not null PRIMARY KEY 
, zzzz varchar 
     ); 

CREATE Table member 
(id SERIAL not null PRIMARY KEY 
, language_id integer not null DEFAULT 0 
, area_id  integer not null REFERENCES area(id) 
, company_id integer 
, external_source_id integer 
, status  integer not null DEFAULT 0 
, name varchar not null 
, zip_code  varchar not null 
, phone_number varchar default NULL 
, using_email_service boolean not null DEFAULT False 
, edited_date timestamp(0) without time zone default NULL 
, created_date timestamp(0) without time zone not null 
, hiding_on_own_network  boolean not null DEFAULT False 
, staff  boolean not null DEFAULT False 
, superuser boolean not null DEFAULT False 
, external_id varchar default NULL 
     ); 

CREATE TABLE advert 
(id SERIAL NOT NULL PRIMARY KEY 
, user_id  integer NOT NULL REFERENCES member(id) 
, advert_category_id integer NOT NULL DEFAULT 0 
, currency_id integer NOT NULL DEFAULT 0 
, advert_kind_id  integer NOT NULL DEFAULT 0 
, advert_price_id  integer 
, external_source_id integer 
, status  integer NOT NULL DEFAULT 0 
, type integer NOT NULL DEFAULT 0 
, title  varchar NOT NULL 
, description text NOT NULL 
, price  numeric(10,2) default NULL 
, accepting_bids  boolean NOT NULL DEFAULT False 
, promoted  boolean NOT NULL DEFAULT False 
, edited_date timestamp(0) without time zone default NULL 
, created_date timestamp(0) without time zone NOT NULL 
, archived_date  timestamp(0) without time zone default NULL 
, views  integer NOT NULL DEFAULT 0 
, checked_date timestamp(0) without time zone default NULL 
, archived_by_cron  boolean NOT NULL DEFAULT False 
, unarchived_by_cron boolean NOT NULL DEFAULT False 
, containting_forbidden_words boolean NOT NULL DEFAULT False 
, external_id varchar default NULL 
     ); 

CREATE INDEX advert_created_date_idx ON advert (created_date); 

CREATE Table network_area_flatdeep 
     -- the surrogate key in a junction table is questionable 
(id SERIAL not null PRIMARY KEY 
, network_id integer not null -- REFERENCES network(id) ON DELETE CASCADE 
, area_id  integer not null REFERENCES area(id) ON DELETE CASCADE 
, created_date timestamp(0) without time zone not null 
     -- the date in the below constraint is questionable 
, CONSTRAINT area_flatdeep_idx_uq UNIQUE (area_id, network_id, created_date) 
     ); 
CREATE INDEX idx_c29e880034128b91 ON network_area_flatdeep(network_id); 
CREATE INDEX idx_c29e8800bd0f409c ON network_area_flatdeep(area_id); 
INSERT INTO area (zzzz) 
SELECT 'Zzzz_' || gs::text 
FROM generate_series(1,39) gs 
     ; 

INSERT INTO network_area_flatdeep 
     -- the surrogate key in a junction table is questionable 
(network_id , area_id , created_date) 
SELECT gs % 7 , aa.id, now() 
FROM generate_series(1,76) gs 
JOIN area aa ON aa.id = 1+gs % 39 
     ; 


INSERT INTO member 
(area_id , name , zip_code, created_date) 
SELECT aa.id 
     , 'Member_'|| gs::text 
     , 'Code_'|| gs::text 
     , now() 
FROM generate_series(1, 10086) gs 
JOIN area aa ON aa.id = 1 + gs % 39 
     ; 
INSERT INTO advert(user_id , title, description, edited_date , created_date) 
SELECT 1+ (gs* 321) % 10086 
     , 'Tit_'|| gs::text 
     , 'Desc_'|| gs::text 
     , now() 
     , now() - (random() * 10000 * '1 sec'::interval) 
from generate_series(1,47569) gs 
     ; 

UPDATE member SET status = 1 WHERE random() < .3; 
UPDATE advert SET status = 1 WHERE random() < .3; 

VACUUM ANALYZE member; 
VACUUM ANALYZE advert; 
VACUUM ANALYZE area; 
VACUUM ANALYZE network_area_flatdeep; 

Truy vấn của tôi thực hiện trong 12ms (PG-9.1), với cùng một gói như OP. (vì vậy đây phải là một vấn đề cấu hình)

+0

Hiệu suất tương tự: 305.512 ms. Tôi hy vọng truy vấn này cũng sẽ nặng hơn nhiều do thiết kế, vì truy vấn con này được chạy cho mọi hàng. Đúng nếu tôi sai. – mauserrifle

+0

Bạn đã sai. (nó là một huyền thoại chỉ được tin bởi những người đã tiếp xúc với mysql) Chỉ cần kiểm tra kế hoạch. Ngược lại: đó là 'IN()' mà * có thể * gây ra vấn đề (trong ngắn hạn: bởi vì nó cần phải loại bỏ các bản sao và NULL) – wildplasser

+0

Ok thú vị :) Làm thế nào tôi thấy rằng nó loại bỏ các bản sao? Để trả lời câu hỏi cuối cùng của bạn: Tất cả đều là FK + Tôi không có các phím tổng hợp vì điều đó làm cho hoạt động ORM phức tạp hơn nhiều trong Doctrine2 (và không được khuyến nghị). Tôi có thể gona rework truy vấn của tôi vì vậy tôi vượt qua trong các giá trị cho IN thông qua PHP. Vì vậy, hãy thực hiện thêm một bước PHP. Mặc dù tôi không coi đây là một giải pháp thực sự. – mauserrifle

0

Một biến thể nhỏ vào một trong các truy vấn của bạn

SELECT a0_.id AS id0 
FROM advert a0_ 
     INNER JOIN member m6_ 
       ON a0_.user_id = m6_.id 
     INNER JOIN area a7_ 
       ON m6_.area_id = a7_.id 
     INNER JOIN (
       SELECT area_id 
       FROM network_area_flatdeep 
       WHERE network_id IN (2) 
       ) network_area_flatdeep n14_ 
       ON a7_.id = n14_.area_id 
WHERE a0_.status IN (1) 
     AND m6_.status IN (1) 
ORDER BY a0_.created_date DESC 
LIMIT 60; 
+0

Không, cùng một hiệu suất: (Tôi cũng đã cập nhật câu hỏi. trên một máy chủ sản xuất bây giờ thay vì hộp ảo địa phương Btw bạn đã thực hiện một lỗi đánh máy.Xóa 'retwork_area_flatdeep' trước n14_ – mauserrifle

0

gì xảy ra nếu bạn bật truy vấn xung quanh? Vì vậy, trước tiên bạn chọn các khu vực và sau đó bạn tham gia vào các thành viên và quảng cáo trên đó. Bạn cũng có thể giới hạn tham gia bằng cách thêm trực tiếp phần WHERE trên trực tiếp JOIN.

SELECT a0_.id AS id0 

FROM area a7_ 
     LEFT JOIN member m6_ 
      ON a7_.id = m6_.area_id AND m6_.status IN (1) 
     LEFT JOIN advert a0_ 
      ON m6_.id = a0_.user_id 

WHERE a7_.id IN (SELECT area_id FROM network_area_flatdeep WHERE network_id IN (1)) 
     AND a0_.status IN (1) 

ORDER BY a0_.created_date DESC 
LIMIT 60; 
+0

Hiệu suất tương tự Đối với cả hai phiên bản bạn đề xuất – mauserrifle