Làm thế nào để tăng tốc độ chọn khác biệt?


16

Tôi có một lựa chọn đơn giản khác biệt trên một số dữ liệu chuỗi thời gian:

SELECT DISTINCT user_id
FROM events
WHERE project_id = 6
AND time > '2015-01-11 8:00:00'
AND time < '2015-02-10 8:00:00';

Và phải mất 112 giây. Đây là kế hoạch truy vấn:

http://explain.depesz.com/s/NTyA

Ứng dụng của tôi phải tạo ra rất nhiều hoạt động riêng biệt và được tính như thế này. Có cách nào nhanh hơn để có được loại dữ liệu này?

Câu trả lời:


19

Có thể bạn không muốn nghe điều này, nhưng lựa chọn tốt nhất để tăng tốc SELECT DISTINCTtránh DISTINCT bắt đầu. Trong nhiều trường hợp (không phải tất cả!) Có thể tránh được với thiết kế cơ sở dữ liệu tốt hơn hoặc truy vấn tốt hơn.

Đôi khi, GROUP BYnhanh hơn, bởi vì nó có một đường dẫn mã khác.

Trong trường hợp cụ thể của bạn , có vẻ như bạn không thể thoát khỏi DISTINCT. Nhưng bạn có thể hỗ trợ truy vấn bằng một chỉ mục chuyên biệt nếu bạn có nhiều truy vấn loại đó:

CREATE INDEX foo ON events (project_id, "time", user_id);

Thêm user_idchỉ hữu ích nếu bạn nhận được quét chỉ mục từ điều này. Theo liên kết để biết chi tiết. Sẽ xóa Bitmap Heap Scan đắt tiền khỏi gói truy vấn của bạn, việc này tiêu tốn 90% thời gian truy vấn.

EXPLAINĐầu ra của bạn cho tôi biết rằng truy vấn phải thu được 2.491 người dùng khác nhau trong số nửa triệu hàng phù hợp. Điều này sẽ không trở nên siêu nhanh, bất kể bạn làm gì, nhưng nó có thể nhanh hơn đáng kể.

Nếu các khoảng thời gian trong các truy vấn của bạn luôn giống nhau, thì việc MATERIALIIZED VIEWgấp user_idmỗi lần (project_id, <fixed time intervall>)sẽ đi một chặng đường dài. Không có cơ hội ở đó với khoảng thời gian khác nhau, mặc dù. Có lẽ bạn ít nhất có thể gấp người dùng mỗi giờ hoặc một số đơn vị thời gian tối thiểu khác, và điều đó sẽ mua đủ hiệu suất để đảm bảo chi phí đáng kể.

Nitpick:
Rất có thể, các vị từ trên "time"thực sự nên là:

AND "time" >= '2015-01-11 8:00:00'
AND "time" <  '2015-02-10 8:00:00';

Ngoài ra:
Không sử dụng timelàm định danh. Đó là một từ dành riêng trong SQL tiêu chuẩn và một loại cơ bản trong Postgres.


Tôi đã đọc một chút về chỉ mục quét, tôi sẽ cho nó một shot.
Sam

Thật không may, khoảng thời gian không cố định.
Sam

@Sam: Vậy truy vấn ví dụ của bạn nhận được nhanh hơn bao nhiêu với chỉ mục được đề xuất?
Erwin Brandstetter

3
@edwin: Chưa thử sản xuất. Tuy nhiên, tôi đã chạy truy vấn ban đầu trên máy cục bộ của mình (có cùng dữ liệu) và mất 3678.780 ms. Sau đó, tôi đã thêm chỉ mục và nó tăng tốc lên tới 170.156 ms. Gói hiện chứa 'Chỉ quét chỉ mục bằng cách sử dụng foo trên các sự kiện'.
Sam

1
@Sam: Đẹp quá! Đó là những gì tôi đã hướng tới.
Erwin Brandstetter

2

Đây là bài kiểm tra của tôi về trường hợp của Sam và câu trả lời của Erwin

drop table t1
create table t1 (id int, user_id int, project_id int, date_time timestamp without time zone) ;

insert into t1 -- 10 million row - size="498 MB"
select row_number() over(), round(row_number() over()/1000), round(row_number() over()/100000) , date
from generate_series('2015-01-01'::date, '2016-12-01'::date,'6 seconds'::interval
) date 
limit 10000000

-- before indexing - 10000000 row - output=100 row - time=2900ms
SELECT DISTINCT user_id
FROM t1
WHERE project_id = 1
AND date_time > '2015-01-01 8:00:00'
AND date_time < '2016-12-01 8:00:00' ;

CREATE INDEX foo ON t1 (project_id, date_time, user_id); -- time process=51.2 secs -- size="387 MB"         

-- after indexing - 10000000 row - output=100 row - time= 75ms (reduce ~ 38 times)
SELECT DISTINCT user_id
FROM t1
WHERE project_id = 1
AND date_time > '2015-01-01 00:00:00'
AND date_time < '2016-12-01 00:00:00' ;

Erwin nói "Có thể bạn không muốn nghe điều này, nhưng tùy chọn tốt nhất để tăng tốc CHỌN DISTINCT là tránh bắt đầu DISTINCT. Trong nhiều trường hợp (không phải tất cả!) Có thể tránh được với thiết kế cơ sở dữ liệu tốt hơn hoặc truy vấn tốt hơn ". Tôi nghĩ anh ấy đúng, chúng ta nên tránh sử dụng "phân biệt, nhóm theo, sắp xếp theo" (nếu có).

Tôi đã gặp một tình huống như trường hợp của Sam và tôi nghĩ Sam có thể sử dụng phân vùng trên bảng sự kiện theo tháng. Nó sẽ giảm kích thước dữ liệu của bạn khi bạn truy vấn, nhưng bạn cần một hàm (pl / pssql) để thực thi thay vì truy vấn ở trên. Hàm sẽ tìm các phân vùng thích hợp (phụ thuộc vào điều kiện) để thực hiện truy vấn.


2
> Tôi nghĩ rằng anh ấy đúng, chúng ta nên tránh sử dụng "phân biệt, nhóm theo, sắp xếp theo" - và cả CHỌN, XÁC NHẬN và CẬP NHẬT. Nếu chúng tôi tránh các cấu trúc này, cơ sở dữ liệu của chúng tôi sẽ rất nhanh!
Greatvovan
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.