2012-07-10 43 views
49

Chúng tôi đang sử dụng Postgresql 9.1.4 làm máy chủ db của chúng tôi. Tôi đã cố gắng để tăng tốc độ bộ thử nghiệm của tôi vì vậy tôi đã nhìn chằm chằm profiling db một chút để xem chính xác những gì đang xảy ra. Chúng tôi đang sử dụng database_cleaner để cắt bớt các bảng ở cuối bài kiểm tra. CÓ Tôi biết giao dịch nhanh hơn, tôi không thể sử dụng chúng trong một số trường hợp nhất định vì vậy tôi không quan tâm đến điều đó.Tốc độ cắt ngắn Postgresql

Những gì tôi quan tâm, là lý do tại sao TRUNCATION mất quá nhiều thời gian (dài hơn DELETE) và tại sao phải mất EVEN LONGER trên máy chủ CI của tôi.

Ngay bây giờ, tại địa phương (trên Macbook Air) một bộ thử nghiệm đầy đủ mất 28 phút. Ghi nhật ký, mỗi lần chúng tôi cắt bớt các bảng ... tức là:

TRUNCATE TABLE table1, table2 -- ... etc 

phải mất hơn 1 giây để thực hiện cắt bớt. Khai thác các bản ghi trên máy chủ CI của chúng tôi (Ubuntu 10.04 LTS), mất 8 giây đầy đủ để cắt ngắn các bảng và một bản dựng mất 84 phút.

Khi tôi chuyển sang chiến lược :deletion, bản dựng cục bộ của tôi mất 20 phút và máy chủ CI đã giảm xuống còn 44 phút. Đây là một sự khác biệt đáng kể và tôi thực sự bị thổi bay vì lý do tại sao điều này có thể xảy ra. Tôi đã tunedthe DB trên máy chủ CI, nó có ram hệ thống 16 GB, shared_buffers 4GB và một ổ SSD. Tất cả những thứ tốt. Làm cách nào có thể:

a. rằng nó SO chậm hơn nhiều so với Macbook Air của tôi với 2 gb ram
b. rằng TRUNCATION chậm hơn rất nhiều so với DELETE khi postgresql docsstate explicitly rằng nó sẽ nhanh hơn nhiều.

Mọi suy nghĩ?

+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? –

+1

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

+0

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

Trả lời

121

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

Vấn đề là DELETETRUNCATE 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.

+3

Và chúng có các loại khóa khác nhau cũng như: khóa bàn vs khóa hàng. –

+0

Cảm ơn bạn đã trả lời toàn diện! Theo tài liệu >> Nó [TRUNCATE] có tác dụng tương tự như DELETE không đủ tiêu chuẩn trên mỗi bảng, nhưng vì nó không thực sự quét các bảng nhanh hơn. Hơn nữa, nó lấy lại không gian đĩa ngay lập tức, thay vì yêu cầu một hoạt động VACUUM tiếp theo. >> Vì vậy, tôi không nghĩ rằng nó thực sự hút bụi sau khi cắt ngắn. Bạn có gợi ý rằng thực tế tôi có 4GB shared_buffers thực sự là một thiệt hại cho hiệu suất? – brad

+0

@brad Đối với trường hợp cụ thể của 'TRUNCATE', vâng, tôi nói rằng sự hiểu biết của tôi là' shared_buffers' lớn có thể làm chậm mọi thứ.Tôi đã không thử nghiệm này bản thân mình, nhưng đó là cách nó âm thanh từ ML thảo luận. Và không, không có 'VACCUM' được thực hiện sau khi cắt ngắn - trong khi truncate * có tác dụng của * một' DELETE FROM' theo sau là 'VACUUM FULL ANALYZE;', nó không thực sự hoạt động theo cách đó hoặc thực hiện các bước đó. –

0

Một vài phương pháp thay thế để xem xét:

  • Tạo một cơ sở dữ liệu rỗng với tĩnh "cố định" dữ liệu trong nó, và chạy thử nghiệm trong đó. Khi bạn làm xong, chỉ cần thả cơ sở dữ liệu, nhanh chóng.
  • Tạo bảng mới có tên "test_ids_to_delete" chứa các cột cho tên bảng và id khóa chính. Cập nhật logic xóa của bạn để chèn tên id/bảng trong bảng này thay vào đó, sẽ nhanh hơn nhiều so với việc chạy xóa. Sau đó, viết kịch bản để chạy "ngoại tuyến" để thực sự xóa dữ liệu, sau khi toàn bộ chạy thử đã kết thúc hoặc qua đêm.

Phương pháp thứ nhất là phương pháp "phòng sạch", trong khi điều này có nghĩa là sẽ có một số dữ liệu thử nghiệm sẽ tồn tại lâu hơn trong cơ sở dữ liệu. Cách tiếp cận "bẩn" với xóa ngoại tuyến là những gì tôi đang sử dụng cho một bộ thử nghiệm với khoảng 20.000 bài kiểm tra. Có, đôi khi có vấn đề do có dữ liệu thử nghiệm "phụ" trong cơ sở dữ liệu dev nhưng đôi khi. Nhưng đôi khi "sự bẩn thỉu" này đã giúp chúng tôi tìm và sửa lỗi vì "sự hỗn loạn" mô phỏng tốt hơn một tình huống thực tế, theo cách mà cách tiếp cận phòng sạch sẽ không bao giờ xảy ra.

5

Brad, chỉ để cho bạn biết. Tôi đã nhìn khá sâu vào một câu hỏi rất giống nhau.

câu hỏi liên quan: 30 tables with few rows - TRUNCATE the fastest way to empty them and reset attached sequences?

cũng hãy nhìn vào vấn đề này và yêu cầu kéo này:

https://github.com/bmabey/database_cleaner/issues/126

https://github.com/bmabey/database_cleaner/pull/127

Ngoài ra chủ đề này: http://archives.postgresql.org/pgsql-performance/2012-07/msg00047.php

Tôi xin lỗi vì viết câu trả lời này, nhưng tôi không tìm thấy ny nhận xét liên kết, có thể bởi vì có quá nhiều bình luận đã có.

+0

xin cảm ơn stanislaw. Tôi thực sự thấy những bài viết đó đã nhắc tôi nâng cấp trình dọn dẹp db để sử dụng cắt ngắn khối lượng. Điều đó, tuy nhiên, đã làm rất ít để giúp tôi. Vẫn còn trên PG có vẻ như chiến lược xóa là nhanh hơn đáng kể, đó là những gì tôi đã kết thúc bằng cách sử dụng. – brad

Các vấn đề liên quan