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_unit
byte 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_unit
sẽ 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_blocks
cơ 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_table
và select * from my_table
khô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 CACHE
khô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_blocks
trở 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 STATUS
xó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.