Bộ nhớ đệm chỉ mục PostgreSQL


16

Tôi gặp khó khăn khi tìm giải thích 'lay' về cách các chỉ mục được lưu trong bộ nhớ cache trong PostgreSQL, vì vậy tôi muốn kiểm tra thực tế về bất kỳ hoặc tất cả các giả định sau:

  1. Các chỉ mục PostgreSQL, như các hàng, trực tiếp trên đĩa nhưng có thể được lưu trữ.
  2. Một chỉ mục có thể hoàn toàn trong bộ đệm hoặc hoàn toàn không.
  3. Nó có được lưu trong bộ nhớ cache hay không phụ thuộc vào tần suất sử dụng (như được xác định bởi trình hoạch định truy vấn).
  4. Vì lý do này, hầu hết các chỉ mục 'hợp lý' sẽ luôn ở trong bộ đệm.
  5. Các chỉ mục sống trong cùng một bộ đệm ( buffer cache?) Như các hàng và do đó, không gian bộ đệm được sử dụng bởi một chỉ mục không có sẵn cho các hàng.


Động lực của tôi để hiểu điều này tiếp theo từ một câu hỏi khác, tôi đã hỏi rằng người ta đã gợi ý rằng các chỉ mục một phần có thể được sử dụng trên các bảng trong đó phần lớn dữ liệu sẽ không bao giờ được truy cập.

Trước khi thực hiện điều này, tôi muốn làm rõ rằng việc sử dụng một chỉ số một phần mang lại hai lợi thế:

  1. Chúng tôi giảm kích thước của chỉ mục trong bộ đệm, giải phóng thêm không gian cho các hàng trong bộ đệm.
  2. Chúng tôi giảm kích thước của B-Tree, dẫn đến phản hồi truy vấn nhanh hơn.

4
Sử dụng một chỉ mục một phần không chỉ hữu ích khi một phần lớn dữ liệu sẽ hiếm khi được truy cập mà còn khi các giá trị nhất định rất phổ biến. Khi một giá trị rất phổ biến, trình hoạch định sẽ sử dụng quét bảng thay vì chỉ mục để bao gồm cả giá trị trong chỉ mục không phục vụ mục đích.
Lươn

Câu trả lời:


19

Chơi một chút với pg_buffercache , tôi có thể nhận được câu trả lời cho một số câu hỏi của bạn.

  1. Điều này khá rõ ràng, nhưng kết quả cho (5) cũng cho thấy câu trả lời là
  2. Tôi vẫn chưa thiết lập một ví dụ tốt cho việc này, vì bây giờ nó có nhiều hơn không :) (Xem phần chỉnh sửa của tôi bên dưới, câu trả lời là KHÔNG .)
  3. Vì người lập kế hoạch là người quyết định có sử dụng chỉ mục hay không, chúng tôi có thể nói , nó quyết định bộ nhớ đệm (nhưng điều này phức tạp hơn)
  4. Các chi tiết chính xác của bộ nhớ đệm có thể được lấy từ mã nguồn, tôi không thể tìm thấy quá nhiều về chủ đề này, ngoại trừ cái này (cũng xem câu trả lời của tác giả ). Tuy nhiên, tôi khá chắc chắn rằng điều này một lần nữa phức tạp hơn nhiều so với đơn giản có hoặc không. (Một lần nữa, từ chỉnh sửa của tôi bạn có thể nhận được một số ý tưởng - vì kích thước bộ nhớ cache được giới hạn, những chỉ số 'nhạy cảm' cạnh tranh cho không gian có sẵn Nếu họ quá nhiều, họ sẽ đá với nhau từ bộ nhớ cache -. Nên câu trả lời là khá NO . )
  5. Là một truy vấn đơn giản với các pg_buffercachechương trình, câu trả lời là CÓ CÓ . Điều đáng lưu ý là dữ liệu bảng tạm thời không được lưu vào bộ nhớ cache ở đây.

BIÊN TẬP

Tôi đã tìm thấy bài viết tuyệt vời của Jeremiah Peschka về lưu trữ bảng và chỉ mục. Với thông tin từ đó, tôi cũng có thể trả lời (2) . Tôi thiết lập một thử nghiệm nhỏ, để bạn có thể tự kiểm tra chúng.

-- we will need two extensions
CREATE EXTENSION pg_buffercache;
CREATE EXTENSION pageinspect;


-- a very simple test table
CREATE TABLE index_cache_test (
      id serial
    , blah text
);


-- I am a bit megalomaniac here, but I will use this for other purposes as well
INSERT INTO index_cache_test
SELECT i, i::text || 'a'
FROM generate_series(1, 1000000) a(i);


-- let's create the index to be cached
CREATE INDEX idx_cache_test ON index_cache_test (id);


-- now we can have a look at what is cached
SELECT c.relname,count(*) AS buffers
FROM 
    pg_class c 
    INNER JOIN pg_buffercache b ON b.relfilenode = c.relfilenode 
    INNER JOIN pg_database d ON (b.reldatabase = d.oid AND d.datname = current_database())
GROUP BY c.relname
ORDER BY 2 DESC LIMIT 10;

             relname              | buffers
----------------------------------+---------
 index_cache_test                 |    2747
 pg_statistic_relid_att_inh_index |       4
 pg_operator_oprname_l_r_n_index  |       4
... (others are all pg_something, which are not interesting now)

-- this shows that the whole table is cached and our index is not in use yet

-- now we can check which row is where in our index
-- in the ctid column, the first number shows the page, so 
-- all rows starting with the same number are stored in the same page
SELECT * FROM bt_page_items('idx_cache_test', 1);

 itemoffset |  ctid   | itemlen | nulls | vars |          data
------------+---------+---------+-------+------+-------------------------
          1 | (1,164) |      16 | f     | f    | 6f 01 00 00 00 00 00 00
          2 | (0,1)   |      16 | f     | f    | 01 00 00 00 00 00 00 00
          3 | (0,2)   |      16 | f     | f    | 02 00 00 00 00 00 00 00
          4 | (0,3)   |      16 | f     | f    | 03 00 00 00 00 00 00 00
          5 | (0,4)   |      16 | f     | f    | 04 00 00 00 00 00 00 00
          6 | (0,5)   |      16 | f     | f    | 05 00 00 00 00 00 00 00
...
         64 | (0,63)  |      16 | f     | f    | 3f 00 00 00 00 00 00 00
         65 | (0,64)  |      16 | f     | f    | 40 00 00 00 00 00 00 00

-- with the information obtained, we can write a query which is supposed to
-- touch only a single page of the index
EXPLAIN (ANALYZE, BUFFERS) 
    SELECT id 
    FROM index_cache_test 
    WHERE id BETWEEN 10 AND 20 ORDER BY id
;

 Index Scan using idx_test_cache on index_cache_test  (cost=0.00..8.54 rows=9 width=4) (actual time=0.031..0.042 rows=11 loops=1)
   Index Cond: ((id >= 10) AND (id <= 20))
   Buffers: shared hit=4
 Total runtime: 0.094 ms
(4 rows)

-- let's have a look at the cache again (the query remains the same as above)
             relname              | buffers
----------------------------------+---------
 index_cache_test                 |    2747
 idx_test_cache                   |       4
...

-- and compare it to a bigger index scan:
EXPLAIN (ANALYZE, BUFFERS) 
SELECT id 
    FROM index_cache_test 
    WHERE id <= 20000 ORDER BY id
;


 Index Scan using idx_test_cache on index_cache_test  (cost=0.00..666.43 rows=19490 width=4) (actual time=0.072..19.921 rows=20000 loops=1)
   Index Cond: (id <= 20000)
   Buffers: shared hit=4 read=162
 Total runtime: 24.967 ms
(4 rows)

-- this already shows that something was in the cache and further pages were read from disk
-- but to be sure, a final glance at cache contents:

             relname              | buffers
----------------------------------+---------
 index_cache_test                 |    2691
 idx_test_cache                   |      58

-- note that some of the table pages are disappeared
-- but, more importantly, a bigger part of our index is now cached

Nói chung, điều này cho thấy các chỉ mục và bảng có thể được lưu vào bộ đệm theo từng trang, do đó câu trả lời cho (2)KHÔNG .

Và một cái cuối cùng để minh họa các bảng tạm thời không được lưu trong bộ nhớ cache ở đây:

CREATE TEMPORARY TABLE tmp_cache_test AS 
SELECT * FROM index_cache_test ORDER BY id FETCH FIRST 20000 ROWS ONLY;

EXPLAIN (ANALYZE, BUFFERS) SELECT id FROM tmp_cache_test ORDER BY id;

-- checking the buffer cache now shows no sign of the temp table

1
+1 Câu trả lời rất hay. Có nghĩa là các bảng tạm thời sống trong RAM không được lưu trữ. Tuy nhiên, tôi tự hỏi, liệu bộ nhớ đệm có xảy ra ngay khi một bảng tạm thời tràn vào đĩa (vì không đủ temp_buffers) - cho toàn bộ bảng hoặc chỉ một phần trên đĩa. Tôi sẽ mong đợi cái sau. Có thể là một thử nghiệm thú vị ..
Erwin Brandstetter

9

Các trang chỉ mục được tìm nạp khi một truy vấn quyết định chúng sẽ hữu ích để cắt giảm lượng dữ liệu bảng cần thiết để trả lời một truy vấn. Chỉ các khối của chỉ mục được điều hướng để thực hiện được đọc. Có, chúng đi vào cùng một nhóm shared_buffers nơi lưu trữ dữ liệu bảng. Cả hai cũng được hỗ trợ bởi bộ đệm của hệ điều hành như một lớp bộ nhớ đệm thứ hai.

Bạn có thể dễ dàng có 0,1% chỉ mục trong bộ nhớ hoặc 100% của chỉ mục. Ý tưởng rằng hầu hết các chỉ mục "'hợp lý" sẽ luôn ở trong bộ đệm "rơi xuống khó khăn khi bạn có các truy vấn chỉ chạm vào một tập hợp con của bảng. Một ví dụ phổ biến là nếu bạn có dữ liệu định hướng thời gian. Thông thường những người thường điều hướng cuối bảng gần đây, hiếm khi nhìn thấy lịch sử cũ. Ở đó bạn có thể tìm thấy tất cả các khối chỉ mục cần thiết để điều hướng đến và xung quanh điểm cuối gần đây trong bộ nhớ, trong khi rất ít cần thiết để điều hướng các bản ghi trước đó ở đó.

Các phần phức tạp của việc triển khai không làm thế nào các khối vào bộ đệm bộ đệm. Đó là quy tắc khi họ rời đi. Cuộc trò chuyện về bộ đệm ẩn bộ đệm PostgreSQL của tôi và các truy vấn mẫu có trong đó có thể giúp bạn hiểu những gì đang diễn ra ở đó và xem những gì thực sự tích lũy trên máy chủ sản xuất. Nó có thể gây ngạc nhiên. Có nhiều hơn nữa về tất cả các chủ đề này trong cuốn sách Hiệu suất cao PostgreSQL 9.0 của tôi .

Các chỉ mục một phần có thể hữu ích vì chúng làm giảm kích thước của chỉ mục và do đó cả hai đều nhanh hơn để điều hướng và để lại nhiều RAM hơn cho bộ nhớ cache những thứ khác. Tuy nhiên, nếu điều hướng chỉ mục của bạn sao cho các phần bạn chạm vào luôn ở trong RAM, thì điều đó có thể không mua được một cải tiến thực sự.

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.