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

Cải thiện hiệu suất của ORDER BY trên tham gia chéo jsonb với nhóm tham gia nội bộ bằng cách

Hãy tạo dữ liệu thử nghiệm trên postgresl 13 với 600 bộ dữ liệu, 45k tệp cf.

  BEGIN; CREATE TABLE cfiles (id KHÓA CHÍNH SERIAL, dataset_id INTEGER NOT NULL, property_values ​​jsonb NOT NULL); INSERT INTO cfiles (dataset_id, property_values) CHỌN 1+ (random () * 600) ::INTEGER AS did, ('{"Tên mẫu":["' || array_to_string (array_agg (DISTINCT prop), '", "') || '"]}') ::jsonb prop FROM (SELECT 1+ (random () * 45000) ::INTEGER AS cid, 'Samp' || (power (random (), 2) * 30) ::INTEGER AS prop FROM generate_series (1.45000 * 4)) foo GROUP BY cid; COMMIT; CREATE TABLE tập dữ liệu (id INTEGER PRIMARY KEY, name TEXT NOT NULL); CHÈN VÀO tập dữ liệu SELECT n, 'dataset' || n FROM (SELECT DISTINCT dataset_id n FROM cfiles) foo; TẠO CHỈ SỐ cfiles_dataset TRÊN cfiles (dataset_id); VACUUM PHÂN TÍCH cfiles; VACUUM PHÂN TÍCH ANALYZE bộ dữ liệu;  

Truy vấn ban đầu của bạn ở đây nhanh hơn rất nhiều, nhưng đó có thể là do postgres 13 thông minh hơn.

  Sắp xếp (chi phí =114127.87..114129.37 hàng =601 chiều rộng =46) (thời gian thực =658.943..659.012 hàng =601 vòng =1) Khóa sắp xếp:datasets.name Phương pháp sắp xếp:nhanh chóng Bộ nhớ:334kB -> GroupAggregate (chi phí =0,57..114100,13 hàng =601 chiều rộng =46) (thời gian thực =13,954..655,916 hàng =601 vòng =1) Khóa nhóm:datasets.id -> Vòng lặp lồng nhau (chi phí =0,57..92009,62 hàng =4416600 chiều rộng =46) (thời gian thực tế =13.373..360.991 hàng =163540 vòng =1) -> Hợp nhất Tham gia (chi phí =0,56..3677,61 hàng =44166 chiều rộng =78) (thời gian thực tế =13.350..113.567 hàng =44166 vòng =1) Hợp nhất Cond:(cfiles.dataset_id =datasets.id) -> Quét chỉ mục bằng cfiles_dataset trên cfiles (chi phí =0,29..3078,75 hàng =44166 chiều rộng =68) (thời gian thực =0,015..69,098 hàng =44166 vòng =1) -> Quét chỉ mục bằng cách sử dụng datasets_pkey trên tập dữ liệu (chi phí =0,28..45,29 hàng =601 chiều rộng =14) (thời gian thực =0,024..0,580 hàng =601 vòng =1) -> Chức năng Quét trên jsonb_array_elements_text sn (chi phí =0 .01..1.00 hàng =100 chiều rộng =32) (thời gian thực tế =0,003..0,004 hàng =4 vòng =44166) Thời gian thực thi:661,978 mili giây  

Truy vấn này đọc một bảng lớn trước tiên (cfiles) và tạo ra ít hàng hơn nhiều do tổng hợp. Do đó, sẽ nhanh hơn để tham gia với các tập dữ liệu sau khi số lượng hàng để tham gia được giảm xuống, chứ không phải trước đó. Hãy di chuyển tham gia đó. Ngoài ra, tôi đã loại bỏ CROSS JOIN không cần thiết, khi có một hàm set-return trong một postgres CHỌN sẽ làm những gì bạn muốn miễn phí.

  SELECT dataset_id, d.name, sample_names FROM (SELECT dataset_id, string_agg (sn, ';') as sample_names FROM (SELECT DISTINCT dataset_id, jsonb_array_elements_text (cfiles.property_values ​​-> 'Sample Name') AS sn FROM cfiles) f GROUP BY dataset_id) g THAM GIA dataset d ON (d.id =g.dataset_id) ORDER BY d.name; KẾ HOẠCH QUERY ------------------------------------------------ -------------------------------------------------- ---------------------------------------------- Sắp xếp (chi phí =536207.44..536207,94 hàng =200 chiều rộng =46) (thời gian thực =264.435..264.502 hàng =601 vòng =1) Khóa sắp xếp:d.name Phương pháp sắp xếp:nhanh chóng Bộ nhớ:334kB -> Hash Tham gia (chi phí =536188.20..536199,79 hàng =200 chiều rộng =46) (thời gian thực =261.404..261,784 hàng =601 vòng =1) Điều kiện băm:(d.id =cfiles.dataset_id) -> Quét Seq trên tập dữ liệu d (chi phí =0,00..10,01 hàng =601 chiều rộng =14) (thời gian thực =0,025..0.124 hàng =601 vòng =1) -> Băm (chi phí =536185,70..536185,70 hàng =200 chiều rộng =36) (thời gian thực =261.361..261.363 hàng =601 vòng =1) Nhóm:1024 Lô:1 Sử dụng bộ nhớ:170kB -> HashAggregate (chi phí =536181.20..536183.70 hàng =200 chiều rộng =36) (thời gian thực =260.805..261.054 hàng =601 vòng =1) Khóa nhóm:cfiles.dataset_id Lô:1 Bộ nhớ Sử dụng:1081kB -> HashAggregate (chi phí =409982,82..507586,70 hàng =1906300 chiều rộng =36) (thời gian thực =244,419..253,094 hàng =18547 vòng =1) Khóa nhóm:cfiles.dataset_id, jsonb_array_elements_text ((cfiles.property_values ​​-> 'Tên mẫu '::text)) Phân vùng theo kế hoạch:4 lô:1 Bộ nhớ sử dụng:13329kB -> ProjectSet (chi phí =0,00..23530,32 hàng =4416600 chiều rộng =36) (thời gian thực =0,030..159,741 hàng =163540 vòng =1) -> Quét Seq trên cfiles (chi phí =0,00..1005,66 hàng =44166 chiều rộng =68) (thời gian thực =0,006..9,588 hàng =44166 vòng =1) Thời gian lập kế hoạch:0,247 ms Thời gian thực hiện:269,362 ms  

Cái đó tốt hơn. Nhưng tôi thấy một LIMIT trong truy vấn của bạn, điều đó có nghĩa là bạn có thể đang làm gì đó như phân trang. Trong trường hợp này, chỉ cần tính toàn bộ truy vấn cho toàn bộ bảng cfiles và sau đó loại bỏ hầu hết các kết quả do LIMIT, NẾU kết quả của truy vấn lớn đó có thể thay đổi liệu một hàng từ tập dữ liệu có được đưa vào kết quả cuối cùng hay không hay không. Nếu đúng như vậy, thì các hàng trong tập dữ liệu không có tệp cf tương ứng sẽ không xuất hiện trong kết quả cuối cùng, điều đó có nghĩa là nội dung của tệp cf sẽ ảnh hưởng đến việc phân trang. Chà, chúng ta luôn có thể gian lận:để biết liệu một hàng từ tập dữ liệu có phải được đưa vào hay không, tất cả những gì bắt buộc là MỘT hàng từ cfiles tồn tại với id đó ...

Vì vậy, để biết hàng bộ dữ liệu nào sẽ được đưa vào kết quả cuối cùng, chúng ta có thể sử dụng một trong hai truy vấn sau:

  CHỌN id TỪ tập dữ liệu TẠI ĐÂY (CHỌN * TỪ cfiles WHERE cfiles.dataset_id =datasets.id) ĐẶT HÀNG THEO tên GIỚI HẠN 20; CHỌN dataset_id FROM (CHỌN id AS dataset_id, tên AS dataset_name TỪ tập dữ liệu ORDER BY dataset_name) f1 WHERE TỒN TẠI (CHỌN * TỪ cfiles WHERE cfiles.dataset_id =f1.dataset_id) ĐẶT HÀNG THEO dataset_name LIMIT 20;  

Chúng mất khoảng 2-3 mili giây. Chúng tôi cũng có thể gian lận:

  TẠO INDEX datasets_name_id ON datasets (name, id);  

Điều này đưa nó xuống khoảng 300 micro giây. Vì vậy, bây giờ chúng ta đã có danh sách dataset_id sẽ thực sự được sử dụng (và không bị vứt bỏ) để chúng ta có thể sử dụng nó để thực hiện tổng hợp chậm lớn chỉ trên các hàng thực sự sẽ có trong kết quả cuối cùng, điều này sẽ tiết kiệm được một lượng lớn công việc không cần thiết ...

« CHỌN dataset_id, string_agg (DISTINCT sn, ';' ĐẶT HÀNG BẰNG sn) làm tên_mẫu TỪ (CHỌN dataset_id, jsonb_array_elements_text (cfiles.property_values ​​-> 'Tên Mẫu') NHƯ sn TỪ ds THAM GIA cfiles SỬ DỤNG (dataset_id)) g GROUP h THAM GIA ds SỬ DỤNG (dataset_id) ĐẶT HÀNG BẰNG dataset_name;

Quá trình này mất khoảng 30ms, tôi cũng đã đặt hàng theo sample_name mà tôi đã quên trước đó. Nó sẽ hoạt động cho trường hợp của bạn. Một điểm quan trọng là thời gian truy vấn không còn phụ thuộc vào kích thước của tập tin bảng, vì nó sẽ chỉ xử lý các hàng thực sự cần thiết.

Vui lòng đăng kết quả;)



  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 thế nào để sử dụng cùng một danh sách hai lần trong mệnh đề WHERE?

  2. giá trị xấu cho kiểu long:- Postgresql, Hibernate, Spring

  3. Tạo chuỗi ngẫu nhiên duy nhất trong plpgsql

  4. Làm thế nào để đăng ký người dùng mới nhận thông báo?

  5. PGError:ERROR:quan hệ delay_jobs không tồn tại (Postgresql, rails 3.04, delay_job error)