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

Chọn hàng đầu tiên trong mỗi nhóm GROUP BY?

DISTINCT ON thường đơn giản nhất và nhanh nhất cho việc này trong PostgreSQL .
(Để tối ưu hóa hiệu suất cho một số khối lượng công việc nhất định, hãy xem bên dưới.)

SELECT DISTINCT ON (customer)
       id, customer, total
FROM   purchases
ORDER  BY customer, total DESC, id;

Hoặc ngắn hơn (nếu không rõ ràng) với số thứ tự của cột đầu ra:

SELECT DISTINCT ON (2)
       id, customer, total
FROM   purchases
ORDER  BY 2, 3 DESC, 1;

Nếu total có thể là NULL (không ảnh hưởng gì cả, nhưng bạn sẽ muốn khớp với các chỉ mục hiện có):

...
ORDER  BY customer, total DESC NULLS LAST, id;

Những điểm chính

DISTINCT ON là một phần mở rộng PostgreSQL của tiêu chuẩn (trong đó chỉ có DISTINCT trên toàn bộ SELECT danh sách được xác định).

Liệt kê bất kỳ số lượng biểu thức nào trong DISTINCT ON mệnh đề, giá trị hàng kết hợp xác định các bản sao. Hướng dẫn sử dụng:

Rõ ràng, hai hàng được coi là khác biệt nếu chúng khác nhau ở ít nhất một giá trị cột. Các giá trị rỗng được coi là bằng nhau trong so sánh này.

Nhấn mạnh đậm của tôi.

DISTINCT ON có thể được kết hợp với ORDER BY . Biểu thức hàng đầu trong ORDER BY phải nằm trong tập hợp các biểu thức trong DISTINCT ON , nhưng bạn có thể sắp xếp lại thứ tự giữa những thứ đó một cách tự do. Ví dụ.
Bạn có thể thêm bổ sung biểu thức thành ORDER BY để chọn một hàng cụ thể từ mỗi nhóm đồng nghiệp. Hoặc, như hướng dẫn sử dụng:

DISTINCT ON (các) biểu thức phải khớp với ORDER BY ngoài cùng bên trái biểu thức). ORDER BY mệnh đề thường sẽ chứa (các) biểu thức cộng xác định mức độ ưu tiên mong muốn của các hàng với DISTINCT ON nhóm.

Tôi đã thêm id là mục cuối cùng để phá vỡ mối quan hệ:
"Chọn hàng có id nhỏ nhất từ mỗi nhóm chia sẻ total cao nhất . "

Để sắp xếp các kết quả theo cách không đồng ý với thứ tự sắp xếp xác định đầu tiên cho mỗi nhóm, bạn có thể lồng truy vấn phía trên trong một truy vấn bên ngoài với một ORDER BY khác . Ví dụ.

Nếu total có thể là NULL, bạn có lẽ nhất muốn hàng có giá trị khác rỗng lớn nhất. Thêm NULLS LAST như đã chứng minh. Xem:

  • Sắp xếp theo ASC cột, nhưng giá trị NULL trước?

SELECT danh sách không bị ràng buộc bởi các biểu thức trong DISTINCT ON hoặc ORDER BY theo bất kỳ cách nào. (Không cần thiết trong trường hợp đơn giản ở trên):

  • Bạn không cần phải bao gồm bất kỳ biểu thức nào trong DISTINCT ON hoặc ORDER BY .

  • Bạn có thể bao gồm bất kỳ biểu thức nào khác trong SELECT danh sách. Đây là công cụ để thay thế các truy vấn phức tạp hơn nhiều bằng các truy vấn con và các hàm tổng hợp / cửa sổ.

Tôi đã thử nghiệm với Postgres phiên bản 8.3 - 13. Nhưng tính năng này đã có ít nhất kể từ phiên bản 7.1, vì vậy về cơ bản luôn luôn.

Chỉ mục

hoàn hảo chỉ mục cho truy vấn trên sẽ là một chỉ mục nhiều cột bao trùm cả ba cột theo trình tự phù hợp và với thứ tự sắp xếp phù hợp:

CREATE INDEX purchases_3c_idx ON purchases (customer, total DESC, id);

Có thể quá chuyên biệt. Nhưng hãy sử dụng nó nếu hiệu suất đọc cho truy vấn cụ thể là rất quan trọng. Nếu bạn có DESC NULLS LAST trong truy vấn, hãy sử dụng chỉ mục tương tự trong chỉ mục để thứ tự sắp xếp phù hợp và chỉ mục có thể áp dụng được.

Hiệu quả / Tối ưu hóa hiệu suất

Cân nhắc chi phí và lợi ích trước khi tạo các chỉ mục phù hợp cho từng truy vấn. Tiềm năng của chỉ mục trên phần lớn phụ thuộc vào phân phối dữ liệu .

Chỉ mục được sử dụng vì nó cung cấp dữ liệu được sắp xếp trước. Trong Postgres 9.2 trở lên, truy vấn cũng có thể được hưởng lợi từ chỉ quét chỉ mục nếu chỉ mục nhỏ hơn bảng bên dưới. Tuy nhiên, chỉ mục phải được quét toàn bộ.

Đối với vài hàng cho mỗi khách hàng (số lượng cao trong cột customer ), điều này rất hiệu quả. Thậm chí nhiều hơn như vậy nếu bạn vẫn cần đầu ra được sắp xếp. Lợi ích giảm dần khi số lượng hàng trên mỗi khách hàng ngày càng tăng.
Tốt nhất, bạn có đủ work_mem để xử lý bước sắp xếp liên quan trong RAM và không tràn ra đĩa. Nhưng nói chung là đặt work_mem quá cao có thể có tác dụng phụ. Xem xét SET LOCAL cho các truy vấn đặc biệt lớn. Tìm số lượng bạn cần với EXPLAIN ANALYZE . Đề cập đến " Đĩa: "trong bước sắp xếp cho thấy cần thêm:

  • Tham số cấu hình work_mem trong PostgreSQL trên Linux
  • Tối ưu hóa truy vấn đơn giản bằng cách sử dụng ĐẶT HÀNG THEO ngày tháng và văn bản

Đối với nhiều hàng cho mỗi khách hàng (số lượng thấp trong cột customer ), quét chỉ mục lỏng lẻo (còn gọi là "bỏ qua quét") sẽ hiệu quả hơn (nhiều), nhưng điều đó không được triển khai cho đến Postgres 14. (Một triển khai dành cho quét chỉ chỉ mục đang được phát triển cho Postgres 15. Xem tại đây và tại đây.)
Đối với bây giờ, có kỹ thuật truy vấn nhanh hơn để thay thế cho điều này. Đặc biệt nếu bạn có một bàn riêng chứa những khách hàng duy nhất, đó là trường hợp sử dụng điển hình. Nhưng cũng có thể nếu bạn không:

  • SELECT DISTINCT chậm hơn mong đợi trên bảng của tôi trong PostgreSQL
  • Tối ưu hóa truy vấn GROUP BY để truy xuất hàng mới nhất cho mỗi người dùng
  • Tối ưu hóa truy vấn tối đa theo nhóm
  • Truy vấn N hàng liên quan cuối cùng trên mỗi hàng

Điểm chuẩn

Xem câu trả lời riêng.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để buộc Postgres sử dụng một chỉ mục cụ thể?

  2. Làm thế nào để sử dụng RETURNING với ON CONFLICT trong PostgreSQL?

  3. Ngăn chặn các mục nhập liền kề / chồng chéo với EXCLUDE trong PostgreSQL

  4. biểu thức chính quy quốc tế hóa trong postgresql

  5. Bất kỳ nhược điểm nào của việc sử dụng văn bản kiểu dữ liệu để lưu trữ chuỗi?