Qcache_free_memory chưa đầy đủ Tôi nhận được rất nhiều Qcache_lowmem_prunes


11

Tôi mới bắt đầu học hỏi với bộ đệm truy vấn cho CMS của chúng tôi.

Bất cứ ai có thể cho tôi biết (hoặc ít nhất đưa ra một dự đoán tốt) tại sao tôi nhận được rất nhiều của Qcache_lowmem_pruneskhi hơn một nửa số Qcache_free_memorylà miễn phí?

query_cache_size=512M
query_cache_limit=1M

Đây là cách nó trông sau khoảng 12 giờ

show status like '%qcach%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| Qcache_free_blocks      | 10338     | 
| Qcache_free_memory      | 297348320 | 
| Qcache_hits             | 10254104  | 
| Qcache_inserts          | 6072945   | 
| Qcache_lowmem_prunes    | 725279    | 
| Qcache_not_cached       | 2237603   | 
| Qcache_queries_in_cache | 48119     | 
| Qcache_total_blocks     | 111346    | 
+-------------------------+-----------+

Đây là cách nó chăm sóc flush query cache;

show status like '%qcach%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| Qcache_free_blocks      | 1         | 
| Qcache_free_memory      | 443559256 | 
| Qcache_hits             | 10307015  | 
| Qcache_inserts          | 6115890   | 
| Qcache_lowmem_prunes    | 725279    | 
| Qcache_not_cached       | 2249405   | 
| Qcache_queries_in_cache | 26455     | 
| Qcache_total_blocks     | 54490     | 
+-------------------------+-----------+

Câu trả lời:


21

Bộ đệm truy vấn là một tính năng rất hay, nhưng đừng cố quá chú ý đến nó và đừng cố làm cho nó quá lớn. Hiểu một số nội bộ của nó có thể sẽ giúp về vấn đề đó.

Bộ đệm truy vấn bắt đầu như một khối lớn của bộ nhớ khả dụng. Sau đó, "khối" được khắc ra khỏi khối lớn này:

  • mỗi truy vấn lưu trữ có một khối
  • kết quả đồng hành của nó mất một khối
  • mỗi bảng được tham chiếu bởi bất kỳ truy vấn được lưu trong bộ nhớ cache nào (cho dù có bao nhiêu truy vấn tham chiếu bảng đó trong bộ đệm) cũng có một khối, mỗi truy vấn mỗi bảng.

Kích thước khối là động, nhưng máy chủ phân bổ tối thiểu query_cache_min_res_unitbyte cho mỗi khối, với mặc định điển hình là 4096 byte.

Bất kỳ truy vấn thời gian nào, kết quả đi kèm và tham chiếu bảng của chúng đều bị xóa khỏi bộ đệm, bằng cách bị vô hiệu hóa bởi các bảng bên dưới thay đổi hoặc bằng cách cắt tỉa để nhường chỗ cho các truy vấn mới hơn, điều này để lại các lỗ hổng lớn cho các khối lớn như vậy, và số lượng "khối miễn phí" thường tăng ... mặc dù nếu hai hoặc nhiều khối liền kề được giải phóng, số lượng "khối miễn phí" chỉ tăng thêm 1 và "khối miễn phí" sẽ không tăng chút nào nếu mới các khối được giải phóng tiếp giáp với một khối đã có sẵn - kích thước của khối miễn phí đó trở nên lớn hơn. Bất kỳ khối bộ nhớ mở nào trong bộ đệm truy vấn đều được tính là 1 khối miễn phí.

Tất nhiên, một khối miễn phí nhỏ hơn query_cache_min_res_unitsẽ không được sử dụng.

Vì vậy, các đoạn bộ nhớ cache truy vấn. Nếu máy chủ muốn lưu trữ một truy vấn mới và không thể sắp xếp các khối miễn phí có kích thước đủ (mô tả đó đơn giản về mặt giả định, vì thuật toán cơ bản rất phức tạp), một thứ khác phải được cắt bỏ ... đó là của bạn Qcache_lowmem_prunes. Có một thuật toán "ít được sử dụng gần đây nhất" (LRU) để quyết định những gì sẽ được cắt tỉa.

Sẽ là hợp lý khi hỏi tại sao máy chủ không phân mảnh bộ nhớ ... nhưng điều đó sẽ không có ý nghĩa. Bộ đệm truy vấn giúp khi có thể nhưng nó hoàn toàn không phải là chiến lược. Bạn không muốn đầu tư thời gian xử lý (đặc biệt là thời gian dành cho khóa toàn cầu) với các nhiệm vụ bảo trì không cần thiết.

Nó sẽ phản tác dụng khi máy chủ dành thời gian sắp xếp lại - chống phân mảnh - bộ nhớ trong bộ đệm truy vấn, vì các kết quả được lưu trong bộ nhớ cache thay đổi liên tục và toàn bộ điểm của bộ đệm là để cải thiện hiệu suất.

Khóa toàn cầu là một lý do rất chính đáng tại sao bạn không muốn sử dụng bộ đệm truy vấn quá lớn ... máy chủ sẽ dành quá nhiều thời gian ở đó vì các truy vấn chờ đến lượt để xem liệu chúng có bị lưu vào bộ nhớ cache không và hiệu suất của bạn sẽ bị ảnh hưởng .

Nhưng về qcache_free_blockscơ bản là một chỉ số của sự phân mảnh không gian tự do. Bây giờ có nhiều khối bộ nhớ khả dụng liên tục tồn tại trong bộ đệm truy vấn. Đối với một truy vấn mới được chèn vào bộ đệm, phải có một khoảng trống đủ lớn để chứa truy vấn, kết quả của nó và (đôi khi) các tham chiếu bảng của nó. Nếu không có, thì thứ khác phải đi ... đó là những gì bạn đang thấy. Lưu ý, một lần nữa, không gian có sẵn không nhất thiết phải liên tục (từ những gì tôi có thể nói bằng cách đọc mã nguồn), nhưng không phải mọi lỗ hổng sẽ được lấp đầy khi có sự phân mảnh.

Nhưng sự phân mảnh có xu hướng tăng dần theo thời gian, đối với một khối lượng công việc nhất định, vì không có gì thường nằm trong bộ đệm truy vấn miễn là bạn có thể mong đợi.

Điều này là do, trong một số cách, bộ đệm truy vấn rất tuyệt vời.

Bất cứ khi nào dữ liệu trong bảng được tham chiếu bởi truy vấn được lưu trong bộ nhớ cache sẽ thay đổi, tất cả các truy vấn có liên quan đến bảng đó sẽ bị xóa khỏi bộ đệm - ngay cả khi thay đổi không ảnh hưởng đến kết quả được lưu trong bộ nhớ cache. Điều này thậm chí đúng nếu bảng thay đổi, nhưng không thay đổi, như trong trường hợp giao dịch InnoDB được khôi phục. Các mục bộ đệm truy vấn tham chiếu bảng đó đã bị xóa.

Ngoài ra, bộ đệm truy vấn được kiểm tra cho mỗi truy vấn đến trước khi máy chủ thực sự phân tích truy vấn. Điều duy nhất phù hợp là một truy vấn khác hoàn toàn giống nhau, theo từng byte. SELECT * FROM my_tableselect * from my_tablekhông giống nhau theo từng byte, do đó, bộ đệm truy vấn không nhận ra chúng là cùng một truy vấn.

FLUSH QUERY CACHEkhông làm trống bộ đệm truy vấn. Nó chống phân mảnh bộ đệm truy vấn, đó là lý do tại sao Qcache_free_blockstrở thành "1." Tất cả các không gian miễn phí được hợp nhất.

RESET QUERY CACHE thực sự xóa (xóa tất cả nội dung của) bộ đệm truy vấn.

FLUSH STATUSxóa các bộ đếm, nhưng đây không phải là điều bạn muốn làm thường xuyên bởi vì điều này thay đổi hầu hết các biến trạng thái trong SHOW STATUS.

Dưới đây là một số cuộc biểu tình nhanh chóng.

Đường cơ sở:

mysql> show status like '%qcache%';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67091120 |
| Qcache_hits             | 0        |
| Qcache_inserts          | 0        |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 1        |
| Qcache_queries_in_cache | 0        |
| Qcache_total_blocks     | 1        |
+-------------------------+----------+

Chạy một truy vấn ...

mysql> select * from junk where id = 2;

Tổng số khối đã tăng thêm 3, chèn thêm 1 và truy vấn trong bộ đệm là 1.

+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67089584 |
| Qcache_inserts          | 1        |
| Qcache_queries_in_cache | 1        |
| Qcache_total_blocks     | 4        |
+-------------------------+----------+

Chạy cùng một truy vấn, nhưng với cách viết hoa khác nhau ...

mysql> SELECT * FROM junk where id = 2;

Truy vấn này được lưu trữ riêng. Tổng số khối chỉ tăng thêm 2 vì chúng tôi đã có một khối được phân bổ cho bảng.

+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67088560 |
| Qcache_inserts          | 2        |
| Qcache_queries_in_cache | 2        |
| Qcache_total_blocks     | 6        |
+-------------------------+----------+

Bây giờ, chúng tôi thay đổi một hàng khác nhau trong bảng.

mysql> update junk set things = 'items' where id = 1;

Cả hai truy vấn và tham chiếu bảng đều không hợp lệ từ bộ đệm, khiến chúng ta có 1 khối miễn phí liền kề, tất cả bộ nhớ đệm được giải phóng và tất cả không gian trống được hợp nhất trong một khối.

+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67091120 |
| Qcache_queries_in_cache | 0        |
| Qcache_total_blocks     | 1        |
+-------------------------+----------+

MySQL sẽ không lưu trữ một truy vấn trong bộ đệm không xác định - chẳng hạn như SELECT NOW();hoặc bất kỳ truy vấn nào bạn nói cụ thể là không lưu vào bộ đệm. SELECT SQL_NO_CACHE ...là chỉ thị để báo cho máy chủ không lưu trữ kết quả vào bộ đệm. Nó hữu ích cho việc đo điểm chuẩn thời gian thực hiện của truy vấn khi bộ đệm tạo cho bạn phản hồi nhanh về mặt thực thi trong các lần thực hiện tiếp theo.


Trong ví dụ của bạn, có đúng là query_cache_min_res_unit = 512 không? bộ nhớ trống giảm 512 * 3 giữa 1 và 4 khối đã sử dụng và 512 * 2 giữa 4 và 6 khối được sử dụng.
aland

1
@aland đó là một điểm rất tốt. Không, đáng lẽ tôi nên sử dụng giá trị mặc định là 4096. Có vẻ như bộ đệm truy vấn sẽ cắt khối lượng xuống mức nhỏ nhất có thể có của hai sau khi lấp đầy nó, để lại khoảng trống trống ở cuối, sao cho 7/8 toàn bộ 4096 byte được phân bổ ban đầu không bị mắc kẹt. Tôi sẽ phải đào sâu hơn về vấn đề này.
Michael - sqlbot 27/05/2015
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.