Qcache_free_memory가 아직 가득 차지 않았는데 Qcache_lowmem_prunes가 많이 있습니다.


11

방금 CMS의 쿼리 캐시를 다루기 시작했습니다.

내가 할 사람이 왜 나를 (또는 적어도 좋은 추측을 제공) 말할 수 많은Qcache_lowmem_prunes의가 절반 이상시 Qcache_free_memory무료입니다?

query_cache_size=512M
query_cache_limit=1M

약 12 시간 후의 모습입니다

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

이것이 어떻게 보였는가 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     | 
+-------------------------+-----------+

답변:


21

쿼리 캐시는 매우 유용한 기능이지만 너무 많은주의를 기울이고 너무 크게 만들려는 유혹을받지 마십시오. 내부의 일부를 이해하면 아마도 그 점에서 도움이 될 것입니다.

쿼리 캐시는 사용 가능한 메모리의 하나의 큰 연속 청크로 시작합니다. 그런 다음 "블록"이이 큰 블록에서 조각됩니다.

  • 캐시 된 각 쿼리는 블록을 사용합니다
  • 동반자 결과 집합이 차단됩니다
  • 캐시 된 쿼리에서 참조하는 각 테이블 (캐시에 해당 테이블을 참조하는 쿼리 수에 관계없이)도 테이블 당 하나씩 블록을 사용합니다.

블록 크기는 동적이지만 서버 query_cache_min_res_unit는 블록 당 최소 바이트를 할당 하며 일반적인 기본값은 4096 바이트입니다.

기본 테이블이 변경되거나 새로운 쿼리를위한 공간을 확보하기 위해 제거 (prune)함으로써 쿼리, 관련 결과 및 테이블 참조가 캐시에서 제거 될 때마다 새로운 홀의 크기는 커지지 만 블록 크기는 크지 만 "사용 가능한 블록"의 수는 일반적으로 증가합니다. 두 개 이상의 연속 블록이 해제되면 "사용 가능한 블록"의 수는 1 씩만 증가하고 "사용 가능한 블록"은 새로 증가하면 전혀 증가하지 않습니다. 해제 된 블록은 이미 사용 가능한 블록과 인접합니다. 사용 가능한 블록의 크기가 커집니다. 쿼리 캐시에서 사용 가능한 열린 메모리 블록은 1 개의 사용 가능한 블록으로 계산됩니다.

물론, 무료 블록보다 작은 프리 블록 query_cache_min_res_unit은 전혀 사용되지 않습니다.

따라서 쿼리 캐시 조각입니다. 서버가 새로운 쿼리를 캐시하고 충분한 크기의 여유 블록을 배열 할 수없는 경우 (기본 알고리즘이 복잡하기 때문에 설명이 간단합니다) 그 밖의 무언가를 정리해야합니다 Qcache_lowmem_prunes. 정리할 대상을 결정하는 "최근에 사용 된"(LRU) 알고리즘이 있습니다.

서버가 왜 메모리를 조각 모음하지 않는지 물어 보는 것이 합리적 일 것입니다. 쿼리 캐시는 가능할 때 도움이되지만 전혀 전략적이지는 않습니다. 불필요한 유지 관리 작업으로 처리 시간 (특히 전역 잠금에 소요 된 시간)을 투자하고 싶지 않습니다.

캐시 된 결과가 지속적으로 변경되고 캐시의 전체 지점이 성능을 향상시키기 때문에 서버가 쿼리 캐시에서 메모리를 다시 정리 (조각 모음)하는 데 시간이 오래 걸리는 것은 비생산적입니다.

전역 잠금은 지나치게 큰 쿼리 캐시를 사용하지 않으려는 매우 좋은 이유입니다. 서버는 쿼리가 캐시되어 발생하는지 확인하고 성능이 저하 될 때까지 차례를 기다리는 동안 서버에서 너무 많은 시간을 소비합니다. .

그러나 이는 qcache_free_blocks본질적으로 자유 공간 조각화의 지표입니다. 이제 쿼리 캐시에 사용 가능한 메모리의 비 연속 블록이 많이 있습니다. 캐시에 새 쿼리를 삽입하려면 쿼리, 결과 및 (때로는) 테이블 참조를 포함 할 수있는 충분한 여유 공간이 있어야합니다. 그렇지 않다면 다른 것이 있어야합니다 ... 이것은 당신이보고있는 것입니다. 가용 공간이 항상 연속적 일 필요는 없지만 (소스 코드를 읽음으로써 알 수있는 것부터) 조각화가있을 때 모든 구멍이 채워지는 것은 아닙니다.

그러나 조각화는 주어진 워크로드에 대해 시간이 지남에 따라 평준화되는 경향이 있습니다. 일반적으로 예상 한 시간 동안 쿼리 캐시에 아무것도 남아 있지 않기 때문입니다.

이는 어떤 식 으로든 쿼리 캐시가 단순하기 때문에 훌륭하기 때문입니다.

캐시 된 쿼리에서 참조하는 테이블의 데이터가 변경 될 때마다 변경 사항이 캐시 된 결과에 영향을 미치지 않더라도 해당 테이블과 관련된 모든 쿼리가 캐시에서 제거됩니다. 롤백 된 InnoDB 트랜잭션의 경우처럼 테이블이 변경되지만 변경되지 않는 경우에도 마찬가지입니다. 해당 테이블을 참조하는 쿼리 캐시 항목이 이미 제거되었습니다.

또한 서버가 실제로 쿼리를 구문 분석 하기 전에 들어오는 각 쿼리에 대해 쿼리 캐시를 확인 합니다. 일치하는 유일한 것은 정확히 바이트 단위의 다른 쿼리입니다. SELECT * FROM my_tableselect * from my_table쿼리 캐시가 실현되지 않도록 그들은 같은 쿼리있어, 바이트 단위 동일하지 않다.

FLUSH QUERY CACHE쿼리 캐시를 비우지 않습니다. 쿼리 캐시를 조각 모음하므로 Qcache_free_blocks"1"이됩니다. 여유 공간이 모두 통합되었습니다.

RESET QUERY CACHE 실제로 쿼리 캐시를 플러시합니다 (모든 내용을 지 웁니다).

FLUSH STATUS카운터를 지 웁니다. 그러나의 대부분의 상태 변수를 0으로 만들기 때문에 일상적으로 수행하려는 작업이 아닙니다 SHOW STATUS.

다음은 몇 가지 간단한 데모입니다.

기준선 :

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

검색어 실행 ...

mysql> select * from junk where id = 2;

캐시의 총 블록 수는 1이고 총 블록 수는 3 개, 삽입 수는 1 개 증가했습니다.

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

동일한 쿼리를 실행하지만 대문자를 다르게 사용하십시오.

mysql> SELECT * FROM junk where id = 2;

이 쿼리는 별도로 캐시되었습니다. 테이블에 이미 블록이 할당되어 있기 때문에 총 블록 수는 2 만 증가했습니다.

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

이제 테이블에서 다른 행을 변경 합니다.

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

쿼리와 테이블 참조는 캐시에서 무효화되어 1 개의 연속 사용 가능한 블록, 사용 가능한 모든 캐시 메모리 및 사용 가능한 모든 공간이 하나의 블록으로 통합됩니다.

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

MySQL은 결정적이지 않은 캐시 (예 : SELECT NOW();캐시하지 말라고하는 쿼리)에 쿼리를 저장하지 않습니다. SELECT SQL_NO_CACHE ...결과를 캐시에 저장하지 않도록 서버에 지시하는 지시문입니다. 캐시가 후속 실행에 대해 믿을 수 없을 정도로 빠른 응답을 제공 할 때 쿼리의 실제 실행 시간을 벤치마킹하는 데 유용합니다.


귀하의 예에서 query_cache_min_res_unit = 512가 맞습니까? 사용 가능한 메모리는 1 ~ 4 개의 사용 된 블록 사이에서 512 * 3, 4 ~ 6 개의 사용 된 블록 사이에 512 * 2만큼 줄어 듭니다.
aland

1
@aland는 매우 좋은 지적입니다. 아니요, 기본값 4096 을 사용해야 했습니다. 쿼리 캐시가 블록을 채운 후 가능한 가장 작은 2 승으로 자르고 여유 공간을 남겨두고 7/8의 7/8 원래 할당 된 전체 4096 바이트는 좌초되지 않습니다. 나는 이것에 대해 더 깊이 파고 들어야 할 것이다.
Michael-sqlbot
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.