Sự miêu tả
PostgreQuery 9.6 trên Linux, kích thước của tags_tmp
bảng ~ 30 GB (10 triệu hàng), tags
là một text[]
và chỉ có 6 giá trị.
tags_tmp(id int, tags text[], maker_date timestamp, value text)
id tags maker_date value
1 {a,b,c} 2016-11-09 This is test
2 {a} 2016-11-08 This is test
3 {b,c} 2016-11-07 This is test
4 {c} 2016-11-06 This is test
5 {d} 2016-11-05 This is test
Tôi cần lấy dữ liệu với bộ lọc trên tags
cũng như order by
trên maker_date desc
. Tôi có thể tạo một chỉ mục trên cả hai tags & maker_date desc
cột không?
Nếu không, bạn có thể đề xuất ý tưởng khác?
Ví dụ truy vấn
select id, tags, maker_date, value
from tags_tmp
where tags && array['a','b']
order by maker_date desc
limit 5 offset 0
Mã SQL:
create index idx1 on tags_tmp using gin (tags);
create index idx2 on tags_tmp using btree(maker_date desc);
explain (analyse on, costs on, verbose)
select id, tags, maker_date, value
from tags_tmp
where tags && array['funny','inspiration']
order by maker_date desc
limit 5 offset 0 ;
Giải thích kết quả:
Limit (cost=233469.63..233469.65 rows=5 width=116) (actual time=801.482..801.483 rows=5 loops=1)
Output: id, tags, maker_date, value
-> Sort (cost=233469.63..234714.22 rows=497833 width=116) (actual time=801.481..801.481 rows=5 loops=1)
Output: id, tags, maker_date, value
Sort Key: tags_tmp.maker_date DESC
Sort Method: top-N heapsort Memory: 25kB
-> Bitmap Heap Scan on public.tags_tmp (cost=6486.58..225200.81 rows=497833 width=116) (actual time=212.982..696.650 rows=366392 loops=1)
Output: id, tags, maker_date, value
Recheck Cond: (tags_tmp.tags && '{funny,inspiration}'::text[])
Heap Blocks: exact=120034
-> Bitmap Index Scan on idx1 (cost=0.00..6362.12 rows=497882 width=0) (actual time=171.742..171.742 rows=722612 loops=1)
Index Cond: (tags_tmp.tags && '{funny,inspiration}'::text[])
Planning time: 0.185 ms
Execution time: 802.128 ms
Thêm thông tin
Tôi đã thử nghiệm với việc sử dụng chỉ mục một phần cho chỉ một thẻ, tất nhiên, nó nhanh hơn. Nhưng tôi có nhiều thẻ , ví dụ : create index idx_tmp on tags_tmp using btree (maker_date desc) where (tags && array['tag1') or tags && array['tag2'] or ... or tags && array['tag6']
. Và tôi đã thử nghiệm giữa tags && array['tag1']
và 'tag1' = any(tags)
, hiệu suất là như nhau.
text[]
chỉ có 6 giá trị =a, b, c, d, e, f
. Ví dụ:tags={a,b,c}, tags={a}, tags={a,c}, tags={a,b,c,d,e,f}, tags={b,f}
vân vân. Nhưng nó không thể có giá trịg->z, A-Z
và vvcreate table tags_tmp(id int primary key not null, tags text[] not null, maker_date timestamp not null, value text)
Về các
distinct
giá trị mảng,tags
cái chứaa
20% hàng của bảngwhere 'a' = any(tags)
, b = 20%where 'b' = any(tags)
, c = 20%where 'c' = any(tags)
, d = 20%where 'd' = any(tags)
, e = 10%where 'e' = any(tags)
, f = 10%where 'f' = any(tags)
.Ngoài ra,
(tags, maker_date)
không phải là duy nhất.Bảng này không chỉ đọc.
Đó là
sort on timestamp
, nhưng ví dụ của tôi cho thấy ngày, xin lỗi về điều đó.
Tình hình hiện tại: tags = 'a' or tags = 'b' or tags = 'c'
và nhiều hơn nữa
(1) Với GIN index
hoặc chuyển đổi text[] to int[]
cũng như chuyển đổi text[] to int
và hơn thế nữa, nó sẽ sử dụng chỉ mục bitmap trên nhiều thẻ. Cuối cùng, sau khi thử nghiệm, tôi quyết định sử dụng giải pháp cũ, thay đổi OR
thành nhiều UNION
mệnh đề, mỗi mệnh đề UNION
sẽ giới hạn số lượng dữ liệu. Tất nhiên, tôi sẽ tạo partial index
cho từng giá trị thẻ cũng như tôi có thể kết hợp với (1) ở trên. Về mặt OFFSET
, nó sẽ sử dụng một hoặc nhiều điều kiện trong WHERE
mệnh đề thay thế.
Thí dụ
EXPLAIN (ANALYSE ON, costs ON, VERBOSE)
SELECT rs.*
FROM (
(SELECT tags,
id,
maker_date
FROM tags_tmp
WHERE 'a' = any(tags)
AND maker_date <= '2016-03-28 05:43:57.779528'::TIMESTAMP
ORDER BY maker_date DESC LIMIT 5)
UNION
(SELECT tags,
id,
maker_date
FROM tags_tmp
WHERE 'b' = any(tags)
AND maker_date <= '2016-03-28 05:43:57.779528'::TIMESTAMP
ORDER BY maker_date DESC LIMIT 5)
UNION
(SELECT tags,
id,
maker_date
FROM tags_tmp
WHERE 'c' = any(tags)
AND maker_date <= '2016-03-28 05:43:57.779528'::TIMESTAMP
ORDER BY maker_date DESC LIMIT 5)) rs
ORDER BY rs.maker_date DESC LIMIT 5 ;
a:2016-11-09
,b:2016-11-09
,c:2016-11-09
như các nút cây và tất cả trong số họ bao gồm một con trỏ để hàng#1
. MongoDB thực sự hỗ trợ các chỉ mục multikey ghép ... Thật không may, PostgreSQL không có, và điều này rất khó chịu. Bạn sẽ phải tạo một bảng riêng biệtid_ref | tag | date
để tạo một cây b tương tự.