24

Tôi không quen thuộc với việc xem xét các kết quả GIẢI ĐÁP GIẢI THÍCH, tôi có một vấn đề lớn với các truy vấn của tôi quá chậm. Tôi đã cố gắng đọc về cách diễn giải kết quả từ một truy vấn giải thích, nhưng tôi vẫn không biết mình nên tìm kiếm điều gì, và điều gì có thể sai. Tôi có cảm giác rằng có một số ánh sáng đỏ lớn nhấp nháy ở đâu đó, tôi chỉ không nhìn thấy nó.Làm thế nào để hiểu một GIẢI PHÁP GIẢI THÍCH

Vì vậy, các truy vấn được khá đơn giản, nó trông như thế này:

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE LIMIT 25 OFFSET 0 

Và kết quả như thế này:

Limit (cost=0.00..161.07 rows=25 width=1245) (actual time=35.232..38.694 rows=25 loops=1) 
    -> Index Scan using index_cars_onsale_on_brand_and_model_name on cars (cost=0.00..1179.06 rows=183 width=1245) (actual time=35.228..38.652 rows=25 loops=1) 
     Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text)) 
     Filter: has_auto_gear" 
Total runtime: 38.845 ms 

Một nền chút: Tôi đang trên PostgreSQL 9.1.6, chạy trên cơ sở dữ liệu chuyên dụng của Herokus. DB của tôi có RAM 7,5Gb aprox, các bảng ô tô chứa 3,1M hàng và một 2,0 triệu aprox của các hàng có sales_state = 'onsale'. Bảng có 170 cột. Chỉ mục mà nó sử dụng trông giống như thế này:

CREATE INDEX index_cars_onsale_on_brand_and_model_name 
    ON cars 
    USING btree 
    (brand COLLATE pg_catalog."default" , model_name COLLATE pg_catalog."default") 
    WHERE sales_state::text = 'onsale'::text; 

Bất cứ ai nhìn thấy một số vấn đề rõ ràng lớn?

EDIT:

SELECT pg_relation_size('cars'), pg_total_relation_size('cars'); 

pg_relation_size: 2058444800 pg_total_relation_size: 4900126720

SELECT pg_relation_size('index_cars_onsale_on_brand_and_model_name'); 

pg_relation_size: 46301184

SELECT avg(pg_column_size(cars)) FROM cars limit 5000; 

trung bình: 636,9732567210792995

KHÔNG THE LIMIT:

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE 

Bitmap Heap Scan on cars (cost=12.54..1156.95 rows=183 width=4) (actual time=17.067..55.198 rows=2096 loops=1) 
    Recheck Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text) AND ((sales_state)::text = 'onsale'::text)) 
    Filter: has_auto_gear 
    -> Bitmap Index Scan on index_cars_onsale_on_brand_and_model_name (cost=0.00..12.54 rows=585 width=0) (actual time=15.211..15.211 rows=7411 loops=1)" 
     Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text)) 
Total runtime: 56.851 ms 
+0

Hãy thử hút bụi - http://www.postgresql.org/docs/8.1/static/maintenance.html. Các kế hoạch truy vấn có vẻ hợp lý, nhưng thời gian chắc chắn không! –

+0

Ngay trước khi tôi chạy truy vấn, tôi chạy một chân không đầy đủ và một phân tích là tốt ... Trang web của tôi là một công cụ tìm kiếm cho xe ô tô được sử dụng, do đó, thời gian là bởi đến nay không thể chấp nhận. Mục tiêu của tôi là giảm tổng thời gian xuống dưới 1 giây. Bạn có nghĩ rằng đó là tất cả có thể, hoặc tôi sẽ phải tìm một công nghệ khác với một cơ sở dữ liệu hợp lý? –

+0

@NielsKristian Tôi nghĩ rằng một phần lớn của vấn đề có thể là "170 cột" một phần. Bàn lớn đến mức nào? 'SELECT pg_relation_size ('xe hơi'), pg_total_relation_size ('xe hơi');'. Ngoài ra 'SELECT pg_relation_size ('index_cars_onsale_on_brand_and_model_name');' để có được kích thước chỉ mục. Chiều rộng hàng trung bình là bao nhiêu? 'SELECT avg (pg_column_size (cars)) TỪ ô tô thử nghiệm giới hạn 5000; ' –

Trả lời

22

Trong khi không phải là hữu ích cho một kế hoạch đơn giản như thế này, http://explain.depesz.com là thực sự hữu ích. Xem http://explain.depesz.com/s/t4fi. Lưu ý "thống kê" tab và "tùy chọn" kéo xuống.

Những điều cần lưu ý về kế hoạch này:

  • ước tính số lượng hàng (183) là hợp lý so sánh với số lượng hàng thực tế (25). Nó không phải là hàng trăm lần nữa, cũng không phải là nó 1. Bạn đang quan tâm nhiều hơn đến các đơn đặt hàng của cường độ khi nói đến ước tính rowcount, hoặc "1 vs không 1" vấn đề. (Bạn thậm chí không cần độ chính xác "đủ cho công việc của chính phủ" - "đủ gần để tính toán hợp đồng quân sự" sẽ làm). Ước tính chọn lọc và thống kê có vẻ hợp lý.

  • Nó đang sử dụng chỉ mục một phần hai cột được cung cấp (index scan using index_cars_onsale_on_brand_and_model_name), do đó, nó khớp với điều kiện chỉ mục một phần. Bạn có thể thấy điều đó trong Filter: has_auto_gear. Điều kiện tìm kiếm chỉ mục cũng được hiển thị.

  • Hiệu suất truy vấn có vẻ hợp lý do số lượng hàng của bảng có nghĩa là chỉ mục khá lớn, đặc biệt khi chỉ số này vượt quá hai cột. Hàng phù hợp sẽ được phân tán, do đó, có khả năng mỗi hàng sẽ yêu cầu một trang riêng biệt đọc quá.

Tôi thấy không có gì sai ở đây. Tuy nhiên, truy vấn này có thể sẽ được hưởng lợi rất nhiều từ các bản quét chỉ mục của PostgreSQL 9.2.Có thể có một số bảng sưng lên ở đây, nhưng với chỉ số 2 cột và số hàng tuyệt đối, thời gian phản hồi không hoàn toàn không hợp lý, đặc biệt đối với một bảng có 170 cột (!!) có khả năng phù hợp tương đối vài tuples vào mỗi trang. Nếu bạn có thể đủ khả năng một số thời gian chết hãy thử VACUUM FULL để tổ chức lại bảng và xây dựng lại chỉ mục. Điều này sẽ độc quyền khóa bảng trong một thời gian trong khi nó xây dựng lại nó. Nếu bạn không thể đủ thời gian ngừng hoạt động, hãy xem pg_reorg và/hoặc CREATE INDEX CONCURRENTLYALTER INDEX ... RENAME TO.

Bạn có thể thấy EXPLAIN (ANALYZE, BUFFERS, VERBOSE) thông tin mới hơn đôi khi, vì nó có thể hiển thị đệm truy cập vv

Một lựa chọn có thể làm cho truy vấn này nhanh hơn (mặc dù nó có nguy cơ làm chậm các truy vấn khác một chút) là để phân vùng bảng trên brand và bật constraint_exclusion. Xem partitioning.

+0

Xin chào, cảm ơn lời giải thích của bạn, Ngay trước khi tôi chạy truy vấn, tôi đã làm một chân không đầy đủ –

+0

@NielsKristian Xem xét phân vùng nếu tất cả đều thất bại; xem chỉnh sửa để trả lời. Ngoài ra, hãy cân nhắc chỉnh sửa câu hỏi của bạn để hiển thị kết quả 'GIẢI THÍCH (ANALYZE, BUFFERS, VERBOSE)'. –

+0

Cảm ơn tất cả sự giúp đỡ tuyệt vời! Tôi chắc chắn đã có nhiều kiến ​​thức hơn về việc gỡ lỗi SQL. Giải pháp này giúp giảm số cột trong bảng và chính xác hơn về những gì tôi chọn. Thứ hai tôi đã thực hiện một số chỉ số phù hợp tốt hơn. –

0

Vâng ... điều đầu tiên tôi có thể cho bạn biết là cơ sở dữ liệu của bạn đang mong đợi (từ thống kê) để có 183 hàng. Trong thực tế nó đang nhận được 25 hàng. Mặc dù điều đó có lẽ không quá liên quan trong trường hợp này (tức là với những số tiền nhỏ này và không có hoạt động nặng, không phải lo lắng về việc ước tính sai).

Vấn đề lớn hơn (imho) là việc tìm kiếm chỉ mục đơn giản cho 25 hàng đang lấy 35ms. Điều đó có vẻ hơi nhiều. Cơ sở dữ liệu có đủ nặng để có ít nhất tất cả các chỉ mục trong bộ nhớ không? Nó không phải là quá nhiều mặc dù, chỉ có vẻ hơi chậm cho tôi.

Đối với nhìn vào giải thích của bạn, tôi sẽ khuyên bạn nên sử dụng explain.depesz.com: http://explain.depesz.com/s/sA6

+0

Bạn không có nghĩa là 35s không phải là ms? –

+0

@NielsKristian Trông như mili giây đối với tôi. Khi đoán bạn đang đọc nó theo ký hiệu kiểu DE, ví dụ: "123.456.789,50" thay vì kiểu US/AU/UK "123,456,789.50". AFAIK Pg không bản địa hóa thời gian trong EXPLAIN ANALYZE, vì vậy nó phải là 35 mili giây. –