Cá nhân nếu đó là một ngày, hoặc có thể là một ngày, tôi đề nghị luôn luôn lưu trữ nó như một ngày. Nó chỉ dễ dàng hơn để làm việc như là một quy tắc của ngón tay cái.
- Một ngày là 4 byte.
- Một smallint là 2 byte (chúng ta cần hai)
- ... 2 byte: một smallint cho năm
- ... 2 byte: một smallint cho tháng
Bạn có thể có một ngày sẽ hỗ trợ ngày nếu bạn cần, hoặc một ngày smallint
trong năm và tháng sẽ không bao giờ hỗ trợ thêm độ chính xác.
Dữ liệu mẫu
Bây giờ chúng ta hãy xem một ví dụ .. Hãy tạo 1 triệu ngày cho mẫu của chúng tôi. Con số này xấp xỉ 5.000 hàng trong 200 năm từ 1901 đến 2100. Mỗi năm nên có thứ gì đó cho mỗi tháng.
CREATE TABLE foo
AS
SELECT
x,
make_date(year,month,1)::date AS date,
year::smallint,
month::smallint
FROM generate_series(1,1e6) AS gs(x)
CROSS JOIN LATERAL CAST(trunc(random()*12+1+x-x) AS int) AS month
CROSS JOIN LATERAL CAST(trunc(random()*200+1901+x-x) AS int) AS year
;
CREATE INDEX ON foo(date);
CREATE INDEX ON foo (year,month);
VACUUM FULL ANALYZE foo;
Kiểm tra
Đơn giản WHERE
Bây giờ chúng ta có thể kiểm tra những lý thuyết về việc không sử dụng ngày này .. Tôi đã chạy từng thứ một vài lần để làm nóng mọi thứ.
EXPLAIN ANALYZE SELECT * FROM foo WHERE date = '2014-1-1'
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo (cost=11.56..1265.16 rows=405 width=14) (actual time=0.164..0.751 rows=454 loops=1)
Recheck Cond: (date = '2014-04-01'::date)
Heap Blocks: exact=439
-> Bitmap Index Scan on foo_date_idx (cost=0.00..11.46 rows=405 width=0) (actual time=0.090..0.090 rows=454 loops=1)
Index Cond: (date = '2014-04-01'::date)
Planning time: 0.090 ms
Execution time: 0.795 ms
Bây giờ, chúng ta hãy thử phương pháp khác với chúng riêng biệt
EXPLAIN ANALYZE SELECT * FROM foo WHERE year = 2014 AND month = 1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo (cost=12.75..1312.06 rows=422 width=14) (actual time=0.139..0.707 rows=379 loops=1)
Recheck Cond: ((year = 2014) AND (month = 1))
Heap Blocks: exact=362
-> Bitmap Index Scan on foo_year_month_idx (cost=0.00..12.64 rows=422 width=0) (actual time=0.079..0.079 rows=379 loops=1)
Index Cond: ((year = 2014) AND (month = 1))
Planning time: 0.086 ms
Execution time: 0.749 ms
(7 rows)
Công bằng mà nói, chúng không phải là tất cả 0,749 .. một số ít nhiều hoặc ít hơn, nhưng nó không thành vấn đề. Tất cả đều tương đối giống nhau. Nó đơn giản là không cần thiết.
Trong vòng một tháng
Bây giờ, hãy vui vẻ với nó .. Giả sử bạn muốn tìm tất cả các khoảng trong vòng 1 tháng của tháng 1 năm 2014 (cùng tháng chúng tôi đã sử dụng ở trên).
EXPLAIN ANALYZE
SELECT *
FROM foo
WHERE date
BETWEEN
('2014-1-1'::date - '1 month'::interval)::date
AND ('2014-1-1'::date + '1 month'::interval)::date;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo (cost=21.27..2310.97 rows=863 width=14) (actual time=0.384..1.644 rows=1226 loops=1)
Recheck Cond: ((date >= '2013-12-01'::date) AND (date <= '2014-02-01'::date))
Heap Blocks: exact=1083
-> Bitmap Index Scan on foo_date_idx (cost=0.00..21.06 rows=863 width=0) (actual time=0.208..0.208 rows=1226 loops=1)
Index Cond: ((date >= '2013-12-01'::date) AND (date <= '2014-02-01'::date))
Planning time: 0.104 ms
Execution time: 1.727 ms
(7 rows)
So sánh với phương pháp kết hợp
EXPLAIN ANALYZE
SELECT *
FROM foo
WHERE year = 2013 AND month = 12
OR ( year = 2014 AND ( month = 1 OR month = 2) );
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo (cost=38.79..2999.66 rows=1203 width=14) (actual time=0.664..2.291 rows=1226 loops=1)
Recheck Cond: (((year = 2013) AND (month = 12)) OR (((year = 2014) AND (month = 1)) OR ((year = 2014) AND (month = 2))))
Heap Blocks: exact=1083
-> BitmapOr (cost=38.79..38.79 rows=1237 width=0) (actual time=0.479..0.479 rows=0 loops=1)
-> Bitmap Index Scan on foo_year_month_idx (cost=0.00..12.64 rows=421 width=0) (actual time=0.112..0.112 rows=402 loops=1)
Index Cond: ((year = 2013) AND (month = 12))
-> BitmapOr (cost=25.60..25.60 rows=816 width=0) (actual time=0.218..0.218 rows=0 loops=1)
-> Bitmap Index Scan on foo_year_month_idx (cost=0.00..12.62 rows=420 width=0) (actual time=0.108..0.108 rows=423 loops=1)
Index Cond: ((year = 2014) AND (month = 1))
-> Bitmap Index Scan on foo_year_month_idx (cost=0.00..12.38 rows=395 width=0) (actual time=0.108..0.108 rows=401 loops=1)
Index Cond: ((year = 2014) AND (month = 2))
Planning time: 0.256 ms
Execution time: 2.421 ms
(13 rows)
Nó chậm hơn và xấu hơn.
GROUP BY
/ORDER BY
Phương pháp kết hợp,
EXPLAIN ANALYZE
SELECT date, count(*)
FROM foo
GROUP BY date
ORDER BY date;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Sort (cost=20564.75..20570.75 rows=2400 width=4) (actual time=286.749..286.841 rows=2400 loops=1)
Sort Key: date
Sort Method: quicksort Memory: 209kB
-> HashAggregate (cost=20406.00..20430.00 rows=2400 width=4) (actual time=285.978..286.301 rows=2400 loops=1)
Group Key: date
-> Seq Scan on foo (cost=0.00..15406.00 rows=1000000 width=4) (actual time=0.012..70.582 rows=1000000 loops=1)
Planning time: 0.094 ms
Execution time: 286.971 ms
(8 rows)
Và một lần nữa với phương pháp tổng hợp
EXPLAIN ANALYZE
SELECT year, month, count(*)
FROM foo
GROUP BY year, month
ORDER BY year, month;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Sort (cost=23064.75..23070.75 rows=2400 width=4) (actual time=336.826..336.908 rows=2400 loops=1)
Sort Key: year, month
Sort Method: quicksort Memory: 209kB
-> HashAggregate (cost=22906.00..22930.00 rows=2400 width=4) (actual time=335.757..336.060 rows=2400 loops=1)
Group Key: year, month
-> Seq Scan on foo (cost=0.00..15406.00 rows=1000000 width=4) (actual time=0.010..70.468 rows=1000000 loops=1)
Planning time: 0.098 ms
Execution time: 337.027 ms
(8 rows)
Phần kết luận
Nói chung, hãy để những người thông minh làm công việc khó khăn. DHRath rất khó, khách hàng của tôi không trả đủ tiền cho tôi. Tôi đã từng làm những bài kiểm tra này. Tôi đã rất khó khăn để bao giờ kết luận rằng tôi có thể nhận được kết quả tốt hơn date
. Tôi đã ngừng cố gắng.
CẬP NHẬT
@a_horse_with_no_name đề xuất cho thử nghiệm của tôi trong vòng một thángWHERE (year, month) between (2013, 12) and (2014,2)
. Theo ý kiến của tôi, trong khi tuyệt vời đó là một truy vấn phức tạp hơn và tôi muốn tránh nó trừ khi có lợi ích. Than ôi, nó vẫn chậm hơn mặc dù nó gần - đó là phần lớn lấy đi từ bài kiểm tra này. Nó đơn giản là không quan trọng lắm.
EXPLAIN ANALYZE
SELECT *
FROM foo
WHERE (year, month) between (2013, 12) and (2014,2);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo (cost=5287.16..15670.20 rows=248852 width=14) (actual time=0.753..2.157 rows=1226 loops=1)
Recheck Cond: ((ROW(year, month) >= ROW(2013, 12)) AND (ROW(year, month) <= ROW(2014, 2)))
Heap Blocks: exact=1083
-> Bitmap Index Scan on foo_year_month_idx (cost=0.00..5224.95 rows=248852 width=0) (actual time=0.550..0.550 rows=1226 loops=1)
Index Cond: ((ROW(year, month) >= ROW(2013, 12)) AND (ROW(year, month) <= ROW(2014, 2)))
Planning time: 0.099 ms
Execution time: 2.249 ms
(7 rows)
month
có chứa hai số nguyên. Nhưng tôi nghĩ rằng nếu bạn không bao giờ, bao giờ cần đến ngày trong tháng, sử dụng hai số nguyên có lẽ dễ dàng hơn