Thực sự không có ai "cách tốt nhất" để lưu trữ dữ liệu chuỗi thời gian, và nó thực sự phụ thuộc vào một số yếu tố. Tuy nhiên, tôi sẽ tập trung vào hai yếu tố chủ yếu, với chúng là:
(1) Dự án này nghiêm trọng đến mức nào mà nó xứng đáng với nỗ lực của bạn để tối ưu hóa lược đồ?
(2) Các mẫu truy cập truy vấn của bạn thực sự sẽ như thế nào?
Với những câu hỏi đó, hãy thảo luận về một vài lựa chọn lược đồ.
Bàn phẳng
Tùy chọn sử dụng bảng phẳng có liên quan nhiều đến câu hỏi (1) , nếu đây không phải là một dự án nghiêm trọng hoặc quy mô lớn, bạn sẽ thấy dễ dàng hơn nhiều khi không nghĩ quá nhiều về lược đồ và chỉ cần sử dụng một bàn phẳng, như:
CREATE flat_table(
trip_id integer,
tstamp timestamptz,
speed float,
distance float,
temperature float,
,...);
Không có nhiều trường hợp tôi muốn giới thiệu khóa học này, chỉ khi đây là một dự án nhỏ không đảm bảo nhiều thời gian của bạn.
Kích thước và sự kiện
Vì vậy, nếu bạn đã xóa rào cản của câu hỏi (1) và bạn muốn có một lược đồ hiệu suất cao hơn, đây là một trong những lựa chọn đầu tiên để xem xét. Nó bao gồm một số tiêu chuẩn hóa cơ bản, nhưng trích xuất các đại lượng 'chiều' từ các đại lượng 'thực tế' được đo.
Về cơ bản, bạn sẽ muốn một bảng để ghi thông tin về các chuyến đi,
CREATE trips(
trip_id integer,
other_info text);
và một bảng để ghi lại dấu thời gian,
CREATE tstamps(
tstamp_id integer,
tstamp timestamptz);
và cuối cùng là tất cả các sự kiện được đo của bạn, với các tham chiếu khóa ngoài đến các bảng thứ nguyên (đó là meas_facts(trip_id)
tài liệu tham khảo trips(trip_id)
& meas_facts(tstamp_id)
tài liệu tham khảo tstamps(tstamp_id)
)
CREATE meas_facts(
trip_id integer,
tstamp_id integer,
speed float,
distance float,
temperature float,
,...);
Điều này có vẻ không hoàn toàn hữu ích lúc đầu, nhưng nếu bạn có hàng ngàn chuyến đi đồng thời, thì tất cả họ có thể thực hiện các phép đo một lần mỗi giây, vào giây. Trong trường hợp đó, bạn phải ghi lại dấu thời gian mỗi lần cho mỗi chuyến đi, thay vì chỉ sử dụng một mục trong tstamps
bảng.
Ca sử dụng: Trường hợp này sẽ tốt nếu có nhiều chuyến đi đồng thời mà bạn đang ghi dữ liệu và bạn không ngại truy cập tất cả các loại đo lường cùng nhau.
Vì Postgres đọc theo hàng, bất cứ lúc nào bạn muốn, ví dụ, các speed
phép đo trong một khoảng thời gian nhất định, bạn phải đọc toàn bộ hàng từ meas_facts
bảng, điều này chắc chắn sẽ làm chậm một truy vấn, mặc dù nếu tập dữ liệu bạn đang làm việc là không quá lớn, thậm chí bạn sẽ không nhận thấy sự khác biệt.
Chia nhỏ sự kiện đo lường của bạn
Để mở rộng phần cuối cùng thêm một chút nữa, bạn có thể chia các số đo của mình thành các bảng riêng biệt, ví dụ như tôi sẽ hiển thị các bảng về tốc độ và khoảng cách:
CREATE speed_facts(
trip_id integer,
tstamp_id integer,
speed float);
và
CREATE distance_facts(
trip_id integer,
tstamp_id integer,
distance float);
Tất nhiên, bạn có thể thấy làm thế nào điều này có thể được mở rộng cho các phép đo khác.
Trường hợp sử dụng: Vì vậy, điều này sẽ không cung cấp cho bạn một tốc độ cực lớn cho một truy vấn, có lẽ chỉ tăng tốc độ tuyến tính khi bạn truy vấn về một loại đo lường. Điều này là do khi bạn muốn tìm kiếm thông tin về tốc độ, bạn chỉ cần đọc các hàng từ speed_facts
bảng, thay vì tất cả các thông tin bổ sung, không cần thiết sẽ có trong một hàng của meas_facts
bảng.
Vì vậy, bạn chỉ cần đọc số lượng lớn dữ liệu về một loại đo duy nhất, bạn có thể nhận được một số lợi ích. Với trường hợp đề xuất 10 giờ dữ liệu của bạn trong một khoảng thời gian một giây, bạn chỉ đọc được 36.000 hàng, vì vậy bạn sẽ không bao giờ thực sự tìm thấy lợi ích đáng kể từ việc này. Tuy nhiên, nếu bạn đang xem dữ liệu đo tốc độ cho 5.000 chuyến đi trong khoảng 10 giờ, thì bây giờ bạn đang xem đọc 180 triệu hàng. Việc tăng tốc độ tuyến tính cho một truy vấn như vậy có thể mang lại một số lợi ích, miễn là bạn chỉ cần truy cập một hoặc hai loại đo lường tại một thời điểm.
Mảng / HStore / & TOAST
Có lẽ bạn không cần phải lo lắng về phần này, nhưng tôi biết những trường hợp có vấn đề. Nếu bạn cần phải truy cập HUGE lượng dữ liệu chuỗi thời gian, và bạn biết bạn cần phải truy cập vào tất cả của nó trong một khối lớn, bạn có thể sử dụng một cấu trúc mà sẽ làm cho việc sử dụng Bàn TOAST , trong đó chủ yếu lưu trữ dữ liệu của bạn trong lớn hơn, nén phân khúc. Điều này dẫn đến việc truy cập dữ liệu nhanh hơn, miễn là mục tiêu của bạn là truy cập tất cả dữ liệu.
Một ví dụ thực hiện có thể là
CREATE uber_table(
trip_id integer,
tstart timestamptz,
speed float[],
distance float[],
temperature float[],
,...);
Trong bảng này, tstart
sẽ lưu trữ dấu thời gian cho mục nhập đầu tiên trong mảng và mỗi mục tiếp theo sẽ là giá trị của lần đọc cho giây tiếp theo. Điều này đòi hỏi bạn phải quản lý dấu thời gian có liên quan cho từng giá trị mảng trong một phần mềm ứng dụng.
Một khả năng khác là
CREATE uber_table(
trip_id integer,
speed hstore,
distance hstore,
temperature hstore,
,...);
nơi bạn thêm các giá trị đo lường của mình dưới dạng các cặp (khóa, giá trị) của (dấu thời gian, phép đo).
Ca sử dụng: Đây là một triển khai có lẽ tốt hơn dành cho ai đó cảm thấy thoải mái hơn với PostgreSQL và chỉ khi bạn chắc chắn về các mẫu truy cập của mình cần phải là các mẫu truy cập hàng loạt.
Kết luận?
Wow, điều này đã lâu hơn tôi mong đợi, xin lỗi. :)
Về cơ bản, có một số tùy chọn, nhưng có lẽ bạn sẽ nhận được khoản tiền lớn nhất cho đồng tiền của mình bằng cách sử dụng thứ hai hoặc thứ ba, vì chúng phù hợp với trường hợp tổng quát hơn.
PS: Câu hỏi ban đầu của bạn ngụ ý rằng bạn sẽ tải số lượng lớn dữ liệu của mình sau khi tất cả được thu thập. Nếu bạn đang truyền dữ liệu vào ví dụ PostgreQuery của mình, bạn sẽ cần thực hiện thêm một số công việc để xử lý cả việc nhập dữ liệu và khối lượng công việc truy vấn, nhưng chúng ta sẽ để việc đó trong một thời gian khác. ;)