PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Truy vấn N hàng liên quan cuối cùng trên mỗi hàng

Giả sử ít nhất Postgres 9.3.

Chỉ mục

Đầu tiên, chỉ mục đa cột sẽ giúp:

CREATE INDEX observations_special_idx
ON observations(station_id, created_at DESC, id)

created_at DESC phù hợp hơn một chút, nhưng chỉ mục sẽ vẫn được quét ngược với tốc độ gần như tương tự mà không có DESC .

Giả sử created_at được định nghĩa NOT NULL , nếu không, hãy xem xét DESC NULLS LAST trong chỉ mục truy vấn:

  • PostgreSQL sắp xếp theo datetime asc, null trước?

Cột cuối cùng id chỉ hữu ích nếu bạn nhận được một bản quét chỉ chỉ mục từ nó, có thể sẽ không hoạt động nếu bạn thêm nhiều hàng mới liên tục. Trong trường hợp này, hãy xóa id từ chỉ mục.

Truy vấn đơn giản hơn (vẫn chậm)

Đơn giản hóa truy vấn của bạn, lựa chọn con bên trong không giúp ích gì:

SELECT id
FROM  (
  SELECT station_id, id, created_at
       , row_number() OVER (PARTITION BY station_id
                            ORDER BY created_at DESC) AS rn
  FROM   observations
  ) s
WHERE  rn <= #{n}  -- your limit here
ORDER  BY station_id, created_at DESC;

Sẽ nhanh hơn một chút, nhưng vẫn chậm.

Truy vấn nhanh

  • Giả sử bạn có tương đối ít trạm và tương đối nhiều quan sát trên mỗi trạm.
  • Cũng giả sử station_id id được định nghĩa là NOT NULL .

Để trở thành thực sự nhanh chóng, bạn cần tương đương với quét chỉ mục lỏng lẻo (chưa được triển khai trong Postgres). Câu trả lời liên quan:

  • Tối ưu hóa truy vấn GROUP BY để truy xuất bản ghi mới nhất cho mỗi người dùng

Nếu bạn có một bảng stations riêng biệt (có vẻ như có thể xảy ra), bạn có thể mô phỏng điều này bằng JOIN LATERAL (Postgres 9.3+):

SELECT o.id
FROM   stations s
CROSS  JOIN LATERAL (
   SELECT o.id
   FROM   observations o
   WHERE  o.station_id = s.station_id  -- lateral reference
   ORDER  BY o.created_at DESC
   LIMIT  #{n}  -- your limit here
   ) o
ORDER  BY s.station_id, o.created_at DESC;

Nếu bạn không có bảng stations , điều tốt nhất tiếp theo là tạo và duy trì một. Có thể thêm một tham chiếu khóa ngoại để thực thi tính toàn vẹn quan hệ.

Nếu đó không phải là một lựa chọn, bạn có thể chưng cất một bảng như vậy một cách nhanh chóng. Các tùy chọn đơn giản sẽ là:

SELECT DISTINCT station_id FROM observations;
SELECT station_id FROM observations GROUP BY 1;

Nhưng một trong hai sẽ cần quét tuần tự và chậm. Làm cho Postgres sử dụng chỉ mục trên (hoặc bất kỳ chỉ mục btree nào với station_id làm cột hàng đầu) với CTE đệ quy :

WITH RECURSIVE stations AS (
   (                  -- extra pair of parentheses ...
   SELECT station_id
   FROM   observations
   ORDER  BY station_id
   LIMIT  1
   )                  -- ... is required!
   UNION ALL
   SELECT (SELECT o.station_id
           FROM   observations o
           WHERE  o.station_id > s.station_id
           ORDER  BY o.station_id
           LIMIT  1)
   FROM   stations s
   WHERE  s.station_id IS NOT NULL  -- serves as break condition
   )
SELECT station_id
FROM   stations
WHERE  station_id IS NOT NULL;      -- remove dangling row with NULL

Sử dụng nó làm thay thế thả vào cho stations bảng trong truy vấn đơn giản ở trên:

WITH RECURSIVE stations AS (
   (
   SELECT station_id
   FROM   observations
   ORDER  BY station_id
   LIMIT  1
   )
   UNION ALL
   SELECT (SELECT o.station_id
           FROM   observations o
           WHERE  o.station_id > s.station_id
           ORDER  BY o.station_id
           LIMIT  1)
   FROM   stations s
   WHERE  s.station_id IS NOT NULL
   )
SELECT o.id
FROM   stations s
CROSS  JOIN LATERAL (
   SELECT o.id, o.created_at
   FROM   observations o
   WHERE  o.station_id = s.station_id
   ORDER  BY o.created_at DESC
   LIMIT  #{n}  -- your limit here
   ) o
WHERE  s.station_id IS NOT NULL
ORDER  BY s.station_id, o.created_at DESC;

Điều này vẫn sẽ nhanh hơn so với những gì bạn có theo thứ tự cường độ .

SQL Fiddle tại đây (9.6)
db <> fiddle tại đây



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgres kiểu dữ liệu ENUM hoặc KIỂM TRA CONSTRAINT?

  2. Đăng ký và chạy PostgreSQL 9.0 dưới dạng Dịch vụ Windows

  3. Chuyển hướng chèn dựa trên trình kích hoạt Postgres mà không phá vỡ RETURNING

  4. Chuyển từ DB2 sang PostgreSQL - Điều bạn nên biết

  5. Cách đánh giá hiệu suất PostgreSQL bằng Sysbench