2012-11-24 36 views
5

Tôi cần giá trị thấp nhất cho runnerId.Hiệu suất hàm Postgres min

truy vấn này:

SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ; 

mất 80 ms (1968 hàng kết quả).

này:

SELECT min("runnerId") FROM betlog WHERE "marketId" = '107416794' ; 

mất 1.600 ms.

Có cách nào nhanh hơn để tìm mức tối thiểu hay tôi nên tính toán số phút trong chương trình java của mình?

"Result (cost=100.88..100.89 rows=1 width=0)" 
" InitPlan 1 (returns $0)" 
" -> Limit (cost=0.00..100.88 rows=1 width=9)" 
"   -> Index Scan using runneridindex on betlog (cost=0.00..410066.33 rows=4065 width=9)" 
"    Index Cond: ("runnerId" IS NOT NULL)" 
"    Filter: ("marketId" = 107416794::bigint)" 

CREATE INDEX marketidindex 
    ON betlog 
    USING btree 
    ("marketId" COLLATE pg_catalog."default"); 

Một ý tưởng:

SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ORDER BY "runnerId" LIMIT 1 >1600ms 
SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ORDER BY "runnerId" >>100ms 

Làm thế nào một LIMIT có thể làm chậm quá trình truy vấn xuống?

+0

Bạn có chỉ mục trên marketid không? –

+1

[Tìm hiểu lý do tại sao một câu lệnh mất nhiều thời gian để thực hiện được thực hiện bằng lệnh GIẢI THÍCH] (http://wiki.postgresql.org/wiki/Using_EXPLAIN) – raina77ow

+0

có nó có chỉ mục – wutzebaer

Trả lời

8

Những gì bạn cần là một multi-column index:

CREATE INDEX betlog_mult_idx ON betlog ("marketId", "runnerId"); 

Nếu quan tâm, bạn có thể tìm thấy thông tin chi tiết về chỉ số đa cột trong PostgreSQL, liên kết và điểm chuẩn dưới this related question on dba.SE.

Tôi đã làm cách nào để tìm?
Trong chỉ mục nhiều cột, các hàng được sắp xếp (và do đó được nhóm) theo cột đầu tiên của chỉ mục ("marketId") và mỗi cụm lần lượt được sắp xếp theo cột thứ hai của chỉ mục - vì vậy hàng đầu tiên khớp với điều kiện min("runnerId"). Điều này làm cho chỉ mục quét cực nhanh.

Liên quan đến hiệu ứng nghịch lý của LIMIT làm chậm truy vấn - trình lập kế hoạch truy vấn Postgres có điểm yếu ở đó. Cách giải quyết phổ biến là sử dụng CTE (không cần cần thiết trong trường hợp này). Tìm thêm thông tin dưới đây, câu hỏi liên quan chặt chẽ này:
PostgreSQL query taking too long

+0

wow điều này giải quyết được vấn đề, bạn có thể cho một chút nền tảng tại sao không? làm thế nào bạn nhận ra điều đó? – wutzebaer

+1

@wutzebaer: Tôi đã thêm liên kết tới hướng dẫn sử dụng, liên kết tới câu hỏi có thêm thông tin về chỉ mục nhiều cột và một số giải thích. –

+0

nó thực sự là lạ - những gì được giải thích từ truy vấn "xấu"? Đang xử lý 4065 hàng không nên mất 1500 mili giây. –

1

Câu lệnh nhỏ sẽ được thực thi bởi PostgreSQL bằng cách quét tuần tự toàn bộ bảng. Bạn có thể tối ưu hóa truy vấn bằng cách sử dụng phương pháp sau: CHỌN col TỪ ĐẶT HÀNG CÓ THỂ ĐẶT HÀNG BỞI COL ASC LIMIT 1;

+0

chỉ cần sắp xếp nhanh quá >> SELECT "runnerId" TỪ betlog WHERE "marketId" = '107416794' ORDER BY "runnerId" << nhưng khi tôi thêm "LIMIT 1" nó s tại 1600 ms một lần nữa – wutzebaer

+0

Vì vậy, về cơ bản bạn có thể sử dụng thứ tự bằng cách tiếp cận mà không có tuyên bố giới hạn. Điều này sẽ tối ưu hóa truy vấn ở bên cạnh bạn. –

+0

ok, nhưng làm thế nào để giới hạn làm chậm truy vấn? vấn đề của nó là vì tôi muốn sử dụng truy vấn này làm truy vấn phụ – wutzebaer

1

Khi bạn đã có một chỉ mục trên ("runnerId") (hoặc ít nhất là với "runnerId" như cột thứ tự cao) nhưng không có các chỉ mục trên ("marketId", "runnerId") nó so với chi phí của chuyển tất cả các hàng bằng một số phù hợp "marketId" bằng cách sử dụng chỉ mục trên cột đó và chọn số lượng tối thiểu "runnerId" từ thiết lập đó đến chi phí quét bằng chỉ mục trên "runnerId" và dừng khi tìm thấy hàng đầu tiên phù hợp với "marketId". Dựa trên thống kê có sẵn và giả định rằng các giá trị "marketId" sẽ được phân phối ngẫu nhiên trong các mục chỉ mục cho chỉ mục trên "runnerId", nó ước tính chi phí thấp hơn cho phương pháp thứ hai.

Nó cũng ước tính chi phí quét toàn bộ bảng và chọn mức tối thiểu từ các hàng phù hợp cũng như có thể là một số lựa chọn thay thế khác. Nó không luôn luôn sử dụng một loại kế hoạch nhất định, nhưng so sánh chi phí của tất cả các lựa chọn thay thế.

Vấn đề là giả định rằng các giá trị sẽ được phân phối ngẫu nhiên trong phạm vi không nhất thiết đúng (như trong ví dụ này), dẫn đến việc quét phần trăm cao của dãy để tìm các hàng ẩn ở cuối. Đối với một số giá trị của "marketId", trong đó giá trị đã chọn có sẵn gần đầu chỉ số "runnerId", kế hoạch này phải rất nhanh. Đã có cuộc thảo luận trong cộng đồng nhà phát triển PostgreSQL về cách chúng ta có thể thiên vị đối với các kế hoạch "nguy hiểm" về mặt dài nếu phân phối dữ liệu không được giả định và đã có công việc theo dõi nhiều cột thống kê để các giá trị tương quan không chạy vào các vấn đề như vậy. Mong đợi những cải tiến trong lĩnh vực này trong vài phiên bản tiếp theo. Cho đến lúc đó, các đề xuất của Erwin đang nhắm vào mục tiêu về cách giải quyết vấn đề.

Về cơ bản, việc lập kế hoạch hấp dẫn hơn có sẵn hoặc giới thiệu một rào cản tối ưu hóa. Trong trường hợp này, bạn có thể cung cấp một tùy chọn hấp dẫn hơn bằng cách thêm chỉ mục trên ("marketId", "runnerId") - cho phép một cách rất trực tiếp để đến thẳng câu trả lời. Người lập kế hoạch chỉ định chi phí rất thấp cho giải pháp thay thế đó, khiến cho nó được chọn. Nếu bạn ưa thích không thêm chỉ mục, bạn có thể buộc một rào cản tối ưu hóa bằng cách làm một cái gì đó như thế này:

SELECT min("runnerId") 
    FROM (SELECT "runnerId" FROM betlog 
      WHERE "marketId" = '107416794' 
      OFFSET 0) x; 

Khi có một khoản OFFSET (ngay cả đối với một bù đắp của zero) nó buộc subquery được quy hoạch riêng và kết quả của nó được cung cấp cho truy vấn bên ngoài. Tôi hy vọng điều này sẽ chạy trong 80 ms thay vì 1600 ms bạn nhận được mà không có rào cản tối ưu hóa. Tất nhiên, nếu bạn có thể thêm chỉ mục, tốc độ truy vấn khi dữ liệu được lưu trong bộ nhớ cache phải nhỏ hơn 1 ms.