Giả sử id không chỉ UNIQUE - như được thực thi bởi UNIQUE INDEX của bạn - but also NOT NULL . (Cái đó bị thiếu trong định nghĩa bảng của bạn.)
SELECT meta_split.key, meta_split.value, count(*)
FROM voc_cc348779bdc84f8aab483f662a798a6a v
CROSS JOIN LATERAL jsonb_each(v.meta) AS meta_split
GROUP BY meta_split.key, meta_split.value;
Tương đương ngắn hơn:
SELECT meta_split.key, meta_split.value, count(*)
FROM voc_cc348779bdc84f8aab483f662a798a6a v, jsonb_each(v.meta) AS meta_split
GROUP BY 1, 2;
LEFT [OUTER] JOIN bị nhiễu vì kiểm tra sau WHERE meta_split.value IS NOT NULL buộc một INNER JOIN dù sao. Sử dụng CROSS JOIN thay vào đó.
Ngoài ra, vì jsonb không cho phép các khóa trùng lặp ở cùng một cấp (nghĩa là cùng một id chỉ có thể bật lên một lần per (key, value) ), DISTINCT chỉ là tiếng ồn đắt tiền. count(v.id) cũng rẻ hơn. Và count(*) tương đương và rẻ hơn - giả sử id là NOT NULL như đã nêu ở trên cùng.
count(*) có một triển khai riêng biệt
và nhanh hơn một chút so với count(<value>) . Nó khác một chút so với count(v.*) . Nó đếm tất cả các hàng, không có vấn đề gì. Trong khi biểu mẫu khác không tính NULL giá trị.
Đó là, miễn là id không thể là NULL - như đã nêu ở trên. id thực sự phải là PRIMARY KEY , vẫn được triển khai với chỉ mục B-tree duy nhất trong nội bộ và tất cả các cột - chỉ id đây - là NOT NULL ngầm hiểu. Hoặc ít nhất NOT NULL . UNIQUE INDEX không đủ điều kiện thay thế, nó vẫn cho phép NULL các giá trị không được coi là bằng nhau và được phép nhiều lần. Xem:
Ngoài ra, các chỉ mục không được sử dụng ở đây, vì tất cả các hàng phải được đọc. Vì vậy, điều này sẽ không bao giờ là rất rẻ. Nhưng 62k hàng không phải là số lượng hàng làm tê liệt theo bất kỳ phương tiện nào - trừ khi bạn có số lượng khóa lớn trong jsonb cột.
Các tùy chọn còn lại để tăng tốc:
-
Bình thường hóa thiết kế của bạn. Unnesting tài liệu JSON không miễn phí.
-
Duy trì một cái nhìn cụ thể hóa. Tính khả thi và chi phí phụ thuộc nhiều vào cách viết của bạn.
Đó là nơi các chỉ mục có thể đóng một vai trò trở lại ...