Tối ưu hóa PostgreSQL để thử nghiệm nhanh


203

Tôi đang chuyển sang PostgreSQL từ SQLite cho một ứng dụng Rails điển hình.

Vấn đề là thông số kỹ thuật đang chạy trở nên chậm chạp với PG.
Trên SQLite, mất ~ 34 giây, trên PG là ~ 76 giây, chậm hơn gấp 2 lần .

Vì vậy, bây giờ tôi muốn áp dụng một số kỹ thuật để mang lại hiệu suất của thông số kỹ thuật ngang với SQLite mà không cần sửa đổi mã (lý tưởng chỉ bằng cách đặt các tùy chọn kết nối, điều này có lẽ là không thể).

Vài điều rõ ràng từ trên đầu tôi là:

  • RAM Disk (thiết lập tốt với RSpec trên OSX sẽ rất tốt để xem)
  • Các bảng chưa được đăng nhập (nó có thể được áp dụng trên toàn bộ cơ sở dữ liệu để tôi không thay đổi tất cả các tập lệnh không?)

Như bạn có thể đã hiểu, tôi không quan tâm đến độ tin cậy và phần còn lại (DB chỉ là một thứ đáng ghét ở đây).
Tôi cần tận dụng tối đa PG và làm cho nó nhanh nhất có thể .

Câu trả lời hay nhất sẽ mô tả lý tưởng các thủ thuật để làm việc đó, thiết lập và nhược điểm của các thủ thuật đó.

CẬP NHẬT: fsync = off + full_page_writes = offchỉ giảm thời gian xuống ~ 65 giây (~ -16 giây). Khởi đầu tốt, nhưng khác xa mục tiêu 34.

CẬP NHẬT 2: Tôi đã cố gắng sử dụng đĩa RAM nhưng mức tăng hiệu suất nằm trong giới hạn lỗi. Vì vậy, dường như không có giá trị nó.

CẬP NHẬT 3: * Tôi đã tìm thấy nút cổ chai lớn nhất và bây giờ thông số kỹ thuật của tôi chạy nhanh như các SQLite.

Vấn đề là dọn dẹp cơ sở dữ liệu đã cắt ngắn . Rõ ràng SQLite là cách quá nhanh ở đó.

Để "sửa" nó, tôi mở một giao dịch trước mỗi lần kiểm tra và hoàn trả lại vào cuối.

Một số con số cho ~ 700 bài kiểm tra.

  • Cắt ngắn: SQLite - 34s, PG - 76s.
  • Giao dịch: SQLite - 17s, PG - 18s.

Tăng tốc độ gấp 2 lần cho SQLite. Tăng tốc độ gấp 4 lần cho PG.


2
Tôi thực sự nghi ngờ bạn sẽ khiến nó đi nhanh như SQLite. SQLite với một người dùng cực kỳ nhanh. Thiết kế của SQLite rất nhanh với số lượng người dùng thấp và quy mô kém; Thiết kế của PG có quy mô tốt nhưng không nhanh bằng công việc hàng loạt đơn giản chỉ với một người dùng.
Craig Ringer

1
Tôi nhận ra điều đó, nhưng có một trường hợp cụ thể mà tôi hy vọng sẽ tối ưu hóa PG cho (chạy thử) để nó nhanh nhất có thể. Tôi không nhớ nó sẽ chậm hơn một chút ở đó, nhưng 2.2x thì hơi chậm. Hiểu ý tôi chứ?
Dmytrii Nagirniak

+1 Tôi sẽ rất quan tâm đến các bản cập nhật về phương pháp tiếp cận đĩa RAM nếu bạn có bất kỳ kết quả nào liên quan đến điều đó.
tscho

@tscho tôi chắc chắn sẽ đăng nó ở đây. Nhưng cần một chút thời gian vì tôi đang làm việc trên các công cụ khác và "nghiên cứu" các công cụ PG trong "nền".
Dmytrii Nagirniak 23/212

đang chèn dữ liệu vấn đề của bạn hoặc truy vấn ? Nó không rõ ràng từ câu hỏi của bạn.
a_horse_with_no_name

Câu trả lời:


281

Đầu tiên, luôn luôn sử dụng phiên bản mới nhất của PostgreSQL. Cải tiến hiệu suất luôn đến, vì vậy bạn có thể lãng phí thời gian nếu bạn điều chỉnh một phiên bản cũ. Ví dụ, PostgreSQL 9.2 cải thiện đáng kể tốc độTRUNCATE và tất nhiên sẽ thêm các lần quét chỉ mục. Ngay cả các bản phát hành nhỏ phải luôn luôn được tuân theo; xem chính sách phiên bản .

Không

Đừng KHÔNG đặt một tablespace trên một đĩa RAM hoặc không bền lưu trữ khác .

Nếu bạn mất một vùng bảng, toàn bộ cơ sở dữ liệu có thể bị hỏng và khó sử dụng nếu không có công việc quan trọng. Có rất ít lợi thế cho việc này so với việc chỉ sử dụng UNLOGGEDbảng và có nhiều RAM cho bộ nhớ cache.

Nếu bạn thực sự muốn có một hệ thống dựa trên ramdisk, initdbmột cụm hoàn toàn mới trên ramdisk bằng cách sử dụng initdbmột phiên bản PostgreQuery mới trên ramdisk, vì vậy bạn có một phiên bản PostgreQuery hoàn toàn dùng một lần.

Cấu hình máy chủ PostgreSQL

Khi kiểm tra, bạn có thể định cấu hình máy chủ của mình để hoạt động không bền nhưng nhanh hơn .

Đây là một trong những cách sử dụng duy nhất được chấp nhận cho fsync=offcài đặt trong PostgreSQL. Cài đặt này khá nhiều cho PostgreSQL không bận tâm đến việc ghi lệnh hoặc bất kỳ nội dung khó chịu nào khác về bảo vệ toàn vẹn dữ liệu và bảo vệ sự cố, cho phép nó hoàn toàn làm mất dữ liệu của bạn nếu bạn bị mất điện hoặc gặp sự cố hệ điều hành.

Không cần phải nói, bạn không bao giờ nên kích hoạt fsync=offtrong sản xuất trừ khi bạn đang sử dụng PG làm cơ sở dữ liệu tạm thời cho dữ liệu bạn có thể tạo lại từ nơi khác. Nếu và chỉ khi bạn đang tắt fsync thì cũng có thể full_page_writestắt, vì nó không còn hoạt động tốt nữa. Coi chừng đó fsync=offfull_page_writesáp dụng ở cấp độ cụm , vì vậy chúng ảnh hưởng đến tất cả các cơ sở dữ liệu trong trường hợp PostgreQuery của bạn.

Đối với việc sử dụng sản xuất, bạn có thể có thể sử dụng synchronous_commit=offvà thiết lập commit_delay, vì bạn sẽ nhận được nhiều lợi ích giống như fsync=offkhông có rủi ro tham nhũng dữ liệu khổng lồ. Bạn có một cửa sổ nhỏ mất dữ liệu gần đây nếu bạn bật cam kết không đồng bộ - nhưng đó là nó.

Nếu bạn có tùy chọn thay đổi một chút DDL, bạn cũng có thể sử dụng UNLOGGEDcác bảng trong PG 9.1+ để tránh hoàn toàn việc ghi nhật ký WAL và tăng tốc độ thực sự với chi phí của các bảng bị xóa nếu máy chủ gặp sự cố. Không có tùy chọn cấu hình để làm cho tất cả các bảng không bị chặn, nó phải được đặt trong thời gian CREATE TABLE. Ngoài việc tốt cho việc kiểm tra, điều này rất hữu ích nếu bạn có các bảng chứa đầy đủ dữ liệu được tạo hoặc không quan trọng trong cơ sở dữ liệu có chứa những thứ bạn cần để an toàn.

Kiểm tra nhật ký của bạn và xem nếu bạn nhận được cảnh báo về quá nhiều điểm kiểm tra. Nếu là bạn, bạn nên tăng checkpoint_segments . Bạn cũng có thể muốn điều chỉnh checkpoint_completion_target để viết trơn tru.

Điều chỉnh shared_buffersđể phù hợp với khối lượng công việc của bạn. Điều này phụ thuộc vào hệ điều hành, phụ thuộc vào những gì khác đang xảy ra với máy của bạn và yêu cầu một số thử nghiệm và lỗi. Mặc định là cực kỳ bảo thủ. Bạn có thể cần tăng giới hạn bộ nhớ chia sẻ tối đa của HĐH nếu bạn tăng shared_bufferstrên PostgreSQL 9.2 trở xuống; 9.3 trở lên đã thay đổi cách họ sử dụng bộ nhớ dùng chung để tránh điều đó.

Nếu bạn đang sử dụng chỉ một vài kết nối làm nhiều việc, hãy tăng work_memđể cung cấp cho họ nhiều RAM hơn để giải quyết, v.v. Hãy coi chừng work_memcài đặt quá cao có thể gây ra sự cố hết bộ nhớ vì không phải là sắp xếp bộ nhớ mỗi kết nối để một truy vấn có thể có nhiều loại lồng nhau. Bạn chỉ thực sự phải tăng work_memnếu bạn có thể thấy các loại tràn vào đĩa EXPLAINhoặc đăng nhập với log_temp_filescài đặt (được khuyến nghị), nhưng giá trị cao hơn cũng có thể cho phép PG chọn các kế hoạch thông minh hơn.

Như đã nói bởi một poster khác ở đây, thật khôn ngoan khi đặt xlog và các bảng / chỉ mục chính trên các ổ cứng riêng biệt nếu có thể. Các phân vùng riêng biệt là khá vô nghĩa, bạn thực sự muốn các ổ đĩa riêng biệt. Sự tách biệt này có ít lợi ích hơn nhiều nếu bạn đang chạy cùng fsync=offvà hầu như không có gì nếu bạn đang sử dụng UNLOGGEDbảng.

Cuối cùng, điều chỉnh các truy vấn của bạn. Đảm bảo rằng random_page_costseq_page_costphản ánh hiệu suất hệ thống của bạn, đảm bảo effective_cache_sizechính xác, v.v. Sử dụng EXPLAIN (BUFFERS, ANALYZE)để kiểm tra các gói truy vấn riêng lẻ và bật auto_explainmô-đun để báo cáo tất cả các truy vấn chậm. Bạn thường có thể cải thiện đáng kể hiệu năng truy vấn chỉ bằng cách tạo một chỉ mục thích hợp hoặc điều chỉnh các tham số chi phí.

AFAIK không có cách nào để thiết lập toàn bộ cơ sở dữ liệu hoặc cụm UNLOGGED. Thật thú vị khi có thể làm như vậy. Xem xét yêu cầu trong danh sách gửi thư PostgreSQL.

Điều chỉnh hệ điều hành máy chủ

Có một số điều chỉnh bạn cũng có thể làm ở cấp hệ điều hành. Điều chính bạn có thể muốn làm là thuyết phục hệ điều hành không xóa mạnh việc ghi vào đĩa, vì bạn thực sự không quan tâm khi / nếu họ đưa nó vào đĩa.

Trong Linux, bạn có thể kiểm soát điều này bằng các cài đặt của hệ thống con bộ nhớ ảodirty_* , như dirty_writeback_centisecs.

Vấn đề duy nhất với việc điều chỉnh các thiết lập ghi lại quá chậm là việc một chương trình khác bị tuôn ra có thể khiến tất cả các bộ đệm tích lũy của PostgreQuery cũng bị xóa, gây ra các gian hàng lớn trong khi mọi thứ bị chặn. Bạn có thể giảm bớt điều này bằng cách chạy PostgreSQL trên một hệ thống tệp khác, nhưng một số lần xả có thể ở cấp thiết bị hoặc toàn bộ cấp không phải cấp hệ thống tệp, vì vậy bạn không thể dựa vào đó.

Điều chỉnh này thực sự đòi hỏi phải chơi xung quanh với các cài đặt để xem cái gì hoạt động tốt nhất cho khối lượng công việc của bạn.

Trên các hạt nhân mới hơn, bạn có thể muốn đảm bảo rằng nó vm.zone_reclaim_modeđược đặt thành 0, vì nó có thể gây ra các vấn đề hiệu năng nghiêm trọng với các hệ thống NUMA (hầu hết các hệ thống hiện nay) do tương tác với cách quản lý của PostgreQuery shared_buffers.

Truy vấn và điều chỉnh khối lượng công việc

Đây là những thứ mà DO yêu cầu thay đổi mã; họ có thể không phù hợp với bạn. Một số điều bạn có thể áp dụng.

Nếu bạn không xử lý hàng loạt các giao dịch lớn hơn, hãy bắt đầu. Rất nhiều giao dịch nhỏ rất tốn kém, vì vậy bạn nên xử lý hàng loạt bất cứ khi nào có thể và thực tế để thực hiện. Nếu bạn đang sử dụng async, điều này ít quan trọng hơn, nhưng vẫn được khuyến khích cao.

Bất cứ khi nào có thể sử dụng bảng tạm thời. Họ không tạo lưu lượng truy cập WAL, vì vậy họ sẽ nhanh hơn rất nhiều cho việc chèn và cập nhật. Đôi khi, đáng để nhét một loạt dữ liệu vào một bảng tạm thời, thao tác dữ liệu theo cách bạn cần, sau đó thực hiện INSERT INTO ... SELECT ...để sao chép nó vào bảng cuối cùng. Lưu ý rằng các bảng tạm thời là mỗi phiên; nếu phiên của bạn kết thúc hoặc bạn mất kết nối thì bảng tạm thời sẽ biến mất và không có kết nối nào khác có thể thấy nội dung của (các) bảng tạm thời của phiên.

Nếu bạn đang sử dụng PostgreSQL 9.1 hoặc mới hơn, bạn có thể sử dụng UNLOGGEDcác bảng cho dữ liệu bạn có thể mất, như trạng thái phiên. Chúng được hiển thị qua các phiên khác nhau và được bảo tồn giữa các kết nối. Chúng bị cắt cụt nếu máy chủ tắt không rõ ràng để chúng không thể được sử dụng cho bất cứ thứ gì bạn không thể tạo lại, nhưng chúng tuyệt vời cho bộ nhớ cache, chế độ xem cụ thể, bảng trạng thái, v.v.

Nói chung, không DELETE FROM blah;. Sử dụng TRUNCATE TABLE blah;thay thế; sẽ nhanh hơn rất nhiều khi bạn bỏ tất cả các hàng trong một bảng. Cắt bớt nhiều bảng trong một TRUNCATEcuộc gọi nếu bạn có thể. TRUNCATESMặc dù vậy, có một cảnh báo nếu bạn làm nhiều bàn nhỏ lặp đi lặp lại; xem: Tốc độ cắt của Postgresql

Nếu bạn không có chỉ mục trên các khóa ngoại, DELETEs liên quan đến các khóa chính được tham chiếu bởi các khóa ngoại đó sẽ bị chậm khủng khiếp. Đảm bảo tạo các chỉ mục như vậy nếu bạn mong đợi DELETEtừ (các) bảng được tham chiếu. Chỉ số là không cần thiết cho TRUNCATE.

Đừng tạo các chỉ mục bạn không cần. Mỗi chỉ số có một chi phí bảo trì. Cố gắng sử dụng một bộ chỉ mục tối thiểu và để quét chỉ mục bitmap kết hợp chúng thay vì duy trì quá nhiều chỉ mục nhiều cột lớn, đắt tiền. Trường hợp chỉ mục là bắt buộc, hãy thử điền vào bảng trước, sau đó tạo chỉ mục ở cuối.

Phần cứng

Có đủ RAM để chứa toàn bộ cơ sở dữ liệu là một chiến thắng lớn nếu bạn có thể quản lý nó.

Nếu bạn không có đủ RAM, dung lượng lưu trữ càng nhanh thì bạn càng có thể sử dụng tốt hơn. Ngay cả một ổ SSD giá rẻ cũng tạo ra sự khác biệt lớn so với việc quay gỉ. Đừng tin tưởng vào SSD giá rẻ để sản xuất, mặc dù chúng thường không gặp sự cố và có thể ăn dữ liệu của bạn.

Học tập

Cuốn sách của Greg Smith, PostgreQuery 9.0 Hiệu suất cao vẫn có liên quan mặc dù đề cập đến một phiên bản cũ hơn một chút. Nó nên là một tài liệu tham khảo hữu ích.

Tham gia danh sách gửi thư chung PostgreSQL và làm theo nó.

Đọc hiểu:


10
Tôi cũng có thể giới thiệu PostgreSQL 9.0 Hiệu suất cao của @GregSmith, đây thực sự là một bài đọc tuyệt vời. Cuốn sách bao gồm mọi khía cạnh của điều chỉnh hiệu suất từ ​​bố trí đĩa cho đến điều chỉnh truy vấn và cung cấp cho bạn một sự hiểu biết rất tốt về nội bộ PG.
tscho

10
Tôi đã không phát hành bản cập nhật cho cuốn sách dành cho PostgreQuery 9.1, bản phát hành duy nhất kể từ khi xuất bản, vì không có đủ các thay đổi liên quan đến hiệu suất trong 9.1 để đảm bảo.
Greg Smith

3
Tuyệt vời viết. Cũng giống như một bản cập nhật nhỏ, Bạn có thể cần tăng giới hạn bộ nhớ chia sẻ tối đa của hệ điều hành nếu bạn tăng shared_buffers, không còn đúng (đối với hầu hết người dùng) trong PostgreQuery 9.3: postgresql.org/docs/9.3/static/release-9- 3.html # AEN114343
Gunnlaugur Briem

1
@bAFiobo Các thử nghiệm của tôi thường thực hiện nhiều tx ở mức TPS cao ... vì tôi cố gắng mô phỏng sản xuất, bao gồm cả khối lượng công việc nặng đồng thời. Nếu bạn có nghĩa là "kết nối đơn, thử nghiệm tuyến tính" thì tôi đồng ý với bạn.
Craig Ringer

1
stackoverflow.com/questions/11419536/ Nhật XÓA có thể nhanh hơn TRUNCATE cho các bảng có ít hàng, có khả năng là trường hợp trong các thử nghiệm.
Jonathan Crosmer

9

Sử dụng bố trí đĩa khác nhau:

  • đĩa khác nhau cho $ PGDATA
  • đĩa khác nhau cho $ PGDATA / pg_xlog
  • đĩa khác nhau cho các tệp tem (trên mỗi cơ sở dữ liệu $ PGDATA / cơ sở // pssql_tmp) (xem ghi chú về work_mem)

chỉnh sửa postgresql.conf:

  • shared_memory: 30% RAM khả dụng nhưng không quá 6 đến 8GB. Có vẻ tốt hơn khi có ít bộ nhớ chia sẻ (2GB - 4GB) để ghi khối lượng công việc lớn
  • work_mem: chủ yếu cho các truy vấn chọn với sắp xếp / tổng hợp. Đây là mỗi cài đặt kết nối và truy vấn có thể phân bổ giá trị đó nhiều lần. Nếu dữ liệu không thể phù hợp thì đĩa sẽ được sử dụng (pssql_tmp). Kiểm tra "giải thích phân tích" để xem bạn cần bao nhiêu bộ nhớ
  • fsync và syncous_commit: Giá trị mặc định là an toàn nhưng nếu bạn có thể chịu đựng được dữ liệu bị mất thì bạn có thể tắt rồi
  • Random_page_cost: nếu bạn có SSD hoặc mảng RAID nhanh, bạn có thể hạ mức này xuống 2.0 (RAID) hoặc thậm chí thấp hơn (1.1) cho SSD
  • checkpoint_segments: bạn có thể tăng 32 hoặc 64 và thay đổi checkpoint_completion_target thành 0.9. Giá trị thấp hơn cho phép phục hồi sau sự cố nhanh hơn

4
Lưu ý rằng nếu bạn đã chạy với fsync=off, đặt pg_xlog vào một đĩa riêng sẽ không cải thiện nhiều nữa.
intgr

Giá trị 1.1 cho SSD dường như không đủ tiêu chuẩn. Tôi thừa nhận rằng đó là những gì một số chuyên gia đã khuyến cáo một cách mù quáng. Ngay cả SSD cũng nhanh hơn đáng kể cho việc đọc tuần tự so với đọc ngẫu nhiên.
Acumenus

@ABB Có, nhưng bạn cũng có các hiệu ứng bộ đệm bộ đệm hệ điều hành tại nơi làm việc. Tất cả những thông số đó dù sao cũng hơi sóng một chút ...
Craig Ringer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.