Điều này đã xuất hiện một vài lần gần đây, cả trên SO và trên danh sách gửi thư của PostgreSQL.
Các TL; DR cho hai điểm cuối cùng của bạn:
(a) shared_buffers lớn hơn có thể tại sao TRUNCATE là chậm hơn trên máy chủ CI. Cấu hình fsync khác nhau hoặc việc sử dụng phương tiện quay thay vì SSD cũng có thể bị lỗi.
(b) TRUNCATE
có chi phí cố định, nhưng không nhất thiết phải chậm hơn DELETE
, cộng với nó hoạt động hiệu quả hơn. Xem phần giải thích chi tiết sau.
CẬP NHẬT: A significant discussion on pgsql-performance phát sinh từ bài đăng này. Xem this thread.
CẬP NHẬT 2: Các cải tiến đã được thêm vào 9.2beta3 để trợ giúp việc này, xem this post.
lời giải thích chi tiết về TRUNCATE
vs DELETE FROM
:
Trong khi không phải là một chuyên gia về chủ đề này, sự hiểu biết của tôi là TRUNCATE
có chi phí gần như cố định cho mỗi bảng, trong khi DELETE
ít nhất là O (n) với n hàng ; tồi tệ hơn nếu có bất kỳ khóa ngoại nào tham chiếu đến bảng bị xóa.
Tôi luôn giả định rằng chi phí cố định của TRUNCATE
thấp hơn chi phí DELETE
trên một bảng gần trống, nhưng điều này không đúng chút nào.
TRUNCATE table;
làm hơn DELETE FROM table;
Tình trạng của cơ sở dữ liệu sau một TRUNCATE table
là nhiều giống như nếu bạn muốn thay vì chạy:
DELETE FROM table;
VACCUUM (FULL, ANALYZE) table;
(chỉ 9.0+ , xem chú thích cuối trang)
... mặc dù tất nhiên TRUNCATE
không thực sự đạt được hiệu quả của nó với một DELETE
và VACUUM
.
Vấn đề là DELETE
và TRUNCATE
làm những việc khác nhau, vì vậy bạn không chỉ so sánh hai lệnh với kết quả giống hệt nhau.
Một DELETE FROM table;
phép hàng và chết sưng lên để duy trì, cho phép các chỉ số để thực hiện mục đã chết, không cập nhật các bảng thống kê được sử dụng bởi các nhà quy hoạch truy vấn vv
Một TRUNCATE
mang đến cho bạn một bảng hoàn toàn mới và lập chỉ mục như thể chúng chỉ là CREATE
ed. Nó giống như bạn đã xóa tất cả các bản ghi, lập lại bảng và đã thực hiện VACUUM FULL
.
Nếu bạn không quan tâm nếu còn chỗ trống trong bảng vì bạn chuẩn bị thực hiện lại, bạn nên sử dụng DELETE FROM table;
.
Vì bạn không chạy VACUUM
bạn sẽ thấy rằng các hàng chết và mục chỉ mục tích lũy dưới dạng bloat phải được quét rồi bỏ qua; điều này làm chậm tất cả truy vấn của bạn. Nếu các thử nghiệm của bạn không thực sự tạo và xóa tất cả dữ liệu mà bạn có thể không nhận thấy hoặc quan tâm và bạn luôn có thể thực hiện một số VACUUM
hoặc hai phần trong suốt quá trình chạy thử nếu bạn thực hiện. Tốt hơn, hãy đặt các thiết lập autovacuum tích cực để đảm bảo rằng autovacuum thực hiện điều đó cho bạn trong nền.
Bạn vẫn có thể TRUNCATE
tất cả các bảng sau khi bộ thử nghiệm toàn bộ chạy để đảm bảo không có hiệu ứng nào tích hợp trên nhiều lần chạy. Trên 9.0 và mới hơn, VACUUM (FULL, ANALYZE);
trên toàn cầu trên bàn ít nhất là tốt nếu không tốt hơn và dễ dàng hơn rất nhiều.
IIRC Pg có một vài tối ưu hóa có nghĩa là nó có thể nhận thấy khi giao dịch của bạn là giao dịch duy nhất có thể xem bảng và ngay lập tức đánh dấu các khối là miễn phí. Trong thử nghiệm, khi tôi muốn tạo bloat, tôi phải có nhiều hơn một kết nối đồng thời để thực hiện nó. Tôi sẽ không dựa vào điều này, mặc dù.
DELETE FROM table;
là rất rẻ cho các bảng nhỏ không có f/k refs
Để DELETE
tất cả các bản ghi từ một bảng không có tài liệu tham khảo chính nước ngoài để nó, tất cả Thạc đã làm một bảng tuần tự quét và thiết lập xmax
của các bộ tuples gặp phải. Đây là một hoạt động rất rẻ - về cơ bản là đọc tuyến tính và viết bán tuyến tính. AFAIK nó không phải chạm vào các chỉ mục; chúng tiếp tục trỏ đến các bộ phận đã chết cho đến khi chúng được làm sạch bởi một số VACUUM
sau đó cũng đánh dấu các khối trong bảng chỉ chứa các phần tử đã chết miễn phí.
DELETE
chỉ bị đắt tiền nếu có nhiều hồ sơ, nếu có rất nhiều tài liệu tham khảo chính nước ngoài phải được kiểm tra, hoặc nếu bạn đếm tiếp theo các VACUUM (FULL, ANALYZE) table;
cần thiết để phù hợp với TRUNCATE
's ảnh hưởng trong phạm vi chi phí DELETE
của bạn .
Trong các thử nghiệm của tôi ở đây, một số DELETE FROM table;
thường là 4x nhanh hơn TRUNCATE
ở 0.5ms so với 2ms. Đó là một DB thử nghiệm trên một SSD, chạy với fsync=off
vì tôi không quan tâm nếu tôi mất tất cả dữ liệu này. Tất nhiên, DELETE FROM table;
không phải là làm tất cả các công việc tương tự, và nếu tôi theo dõi với một VACUUM (FULL, ANALYZE) table;
đó là một 21ms đắt hơn nhiều, do đó, DELETE
chỉ là một chiến thắng nếu tôi không thực sự cần bảng nguyên sơ.
TRUNCATE table;
làm nhiều việc cố định chi phí và dịch vụ dọn hơn DELETE
Ngược lại, một TRUNCATE
đã làm rất nhiều công việc. Nó phải phân bổ các tệp mới cho bảng, bảng TOAST của nó nếu có, và mọi chỉ mục mà bảng có. Tiêu đề phải được ghi vào các tệp đó và danh mục hệ thống cũng có thể cần cập nhật (không chắc chắn về điểm đó, chưa kiểm tra). Sau đó, nó phải thay thế các tệp cũ bằng các tệp cũ hoặc xóa tệp cũ và phải đảm bảo hệ thống tệp đã bắt kịp các thay đổi với thao tác đồng bộ hóa - fsync() hoặc tương tự - thường xóa tất cả bộ đệm vào đĩa . Tôi không chắc liệu đồng bộ có bị bỏ qua nếu bạn đang chạy với tùy chọn (ăn dữ liệu) fsync=off
hay không.
Tôi đã học gần đây rằng TRUNCATE
cũng phải xóa tất cả bộ đệm của PostgreSQL liên quan đến bảng cũ. Điều này có thể mất một lượng thời gian không nhỏ với số lượng lớn shared_buffers
. Tôi nghi ngờ đây là lý do tại sao nó chậm hơn trên máy chủ CI của bạn.
Số dư
Dù sao, bạn có thể thấy rằng một TRUNCATE
của một bảng có một bảng TOAST liên quan (hầu hết do) và một số chỉ số có thể mất một vài phút. Không lâu, nhưng dài hơn DELETE
từ một chiếc bàn gần trống.
Do đó, bạn có thể nên làm một số DELETE FROM table;
.
-
Lưu ý: trên DBS trước 9.0, CLUSTER table_id_seq ON table; ANALYZE table;
hoặc VACUUM FULL ANALYZE table; REINDEX table;
sẽ là một tương đương gần gũi hơn với TRUNCATE
. Các VACUUM FULL
impl thay đổi thành một tốt hơn một trong 9.0.
Bạn có đang chạy các kiểm tra và cơ sở dữ liệu trên macbook và thử nghiệm và cơ sở dữ liệu trên máy chủ CI không? Có phải các bài kiểm tra và cơ sở dữ liệu trên cùng một máy không? –
Btw, bạn đang làm sai ... bạn không thể xóa cơ sở dữ liệu SAU KHI thử nghiệm. Bạn nên làm điều đó TRƯỚC KHI chạy thử nghiệm. Bạn không thể chắc chắn rằng cơ sở dữ liệu được xóa sau khi kiểm tra. –
Thông số postgresql.conf nào đang được sử dụng? Tôi tự hỏi nếu bạn đang chạy với fsync = off (ok nếu bạn không nhớ mất tất cả dữ liệu của bạn, như trong thử nghiệm) trong trường hợp đó sự cân bằng giữa 'DELETE' và' TRUNCATE' có thể khác nhau. Tôi cũng sẽ quan tâm đến 'shared_buffers' của bạn. –