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 ...