Việc duy trì giá trị tóm tắt rất khó - thật dễ dàng để tạo ra khả năng bế tắc chương trình của bạn.
Nếu bạn thực sự phải làm điều này, bởi vì bạn biết rằng bạn sẽ gặp vấn đề về hiệu suất (chẳng hạn như nhunts hàng trăm hoặc nhiều hơn), thì tốt hơn là tạo một bảng tóm tắt riêng cho nhunts, chẳng hạn như:
CREATE TABLE hunts_summary
(
id_hs bigserial primary key,
id_h integer NOT NULL,
nhunts integer NOT NULL
);
CREATE INDEX hunts_summary_id_h_idx on hunts_summary(id_h);
Kích hoạt cho các cuộc săn:
- chạy cho mỗi hàng được thêm vào, loại bỏ, cập nhật;
- thêm một hàng
(id_h, nhunts) = (NEW.id_h, 1)
trên mỗi phụ trang; - thêm một hàng
(id_h, nhunts) = (OLD.id_h, -1)
trên mỗi lần xóa; - cả hai điều trên khi cập nhật thay đổi
id_h
.
Vì trình kích hoạt sẽ chỉ thêm các hàng mới, nó không khóa các hàng hiện có và do đó nó không thể khóa.
Nhưng điều này là chưa đủ - như được mô tả ở trên, bảng tóm tắt sẽ phát triển các hàng nhanh hơn hoặc nhanh hơn bảng săn, vì vậy nó không hữu ích lắm. Vì vậy, chúng tôi cần thêm một số cách để hợp nhất các hàng hiện có theo định kỳ - một số cách để thay đổi:
id_h nhunts
1 1
1 1
2 1
2 -1
1 1
1 -1
2 1
1 1
2 1
Tới:
id_h nhunts
1 3
2 2
Điều này không nên chạy trên mỗi lần gọi kích hoạt, vì sau đó nó sẽ khá chậm, nhưng nó có thể chạy ngẫu nhiên - ví dụ:mọi lần gọi thứ 1/10 đều ngẫu nhiên. Chức năng này sẽ sử dụng từ khóa "bỏ qua bị khóa" để tránh chạm vào các hàng đã bị khóa, tránh trường hợp có thể xảy ra bế tắc.
Trình kích hoạt như vậy sẽ trông giống như sau:
create or replace function hunts_maintain() returns trigger
as $hunts_maintain$
begin
if (tg_op = 'INSERT') then
insert into hunts_summary(id_h, nhunts)
values (NEW.id_h, 1);
elsif (tg_op = 'DELETE') then
insert into hunts_summary(id_h, nhunts)
values (OLD.id_h, -1);
elsif (tg_op = 'UPDATE' and NEW.id_h!=OLD.id_h) then
insert into hunts_summary(id_h, nhunts)
values (OLD.id_h, -1), (NEW.id_h, 1);
end if;
if (random()*1024 < 1) then
with deleted_ids as (
select id_hs from hunts_summary for update skip locked
),
deleted_nhunts as (
delete from hunts_summary where id_hs in (select id_hs from deleted_ids) returning id_h, nhunts
)
insert into hunts_summary (id_h, nhunts) select id_h, sum(nhunts) from deleted_nhunts group by id_h;
end if;
return NEW;
end;
$hunts_maintain$ language plpgsql;
create trigger hunts_maintain
after insert or update or delete on hunts
for each row execute procedure hunts_maintain();
Trình kích hoạt chạy đủ nhanh trên máy tính xách tay của tôi để chèn 1 triệu hàng để tìm bảng trong 45 giây.
Chế độ xem bên dưới này sẽ giúp bạn dễ dàng trích xuất các nhu cầu hiện tại từ bản tóm tắt. Việc truy vấn sẽ mất một số nhỏ hoặc mili giây ngay cả khi bảng săn tìm được tính bằng tỷ:
create or replace view hunts_summary_view as
select id_h, sum(nhunts) as nhunts
from hunts_summary
group by id_h;