AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 33811
Accepted
Nifle
Nifle
Asked: 2013-01-30 23:30:52 +0800 CST2013-01-30 23:30:52 +0800 CST 2013-01-30 23:30:52 +0800 CST

Qcache_free_memory 未满但我得到了很多 Qcache_lowmem_prunes

  • 772

我刚开始涉足 CMS 的查询缓存。

谁能告诉我(或至少给出一个很好的猜测)为什么当超过一半是免费的时我会得到很多?Qcache_lowmem_prunesQcache_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     | 
+-------------------------+-----------+
mysql performance
  • 1 1 个回答
  • 12792 Views

1 个回答

  • Voted
  1. Best Answer
    Michael - sqlbot
    2013-01-31T20:30:00+08:002013-01-31T20:30:00+08:00

    查询缓存是一个非常好的特性,但不要太在意它,也不要试图让它太大。了解它的一些内部结构可能会在这方面有所帮助。

    查询缓存一开始是一大块连续的可用内存。然后从这个大块中雕刻出“块”:

    • 每个缓存查询占用一个块
    • 它的伴随结果集需要一个块
    • 任何缓存查询引用的每个表(无论缓存中有多少引用该表的查询)也需要一个块,每个表一个块。

    块大小是动态的,但服务器为query_cache_min_res_unit每个块分配最少的字节数,典型的默认值为 4096 字节。

    任何时候从缓存中删除查询、它们的伴随结果和表引用,无论是通过更改基础表而变得无效,还是通过修剪为新查询腾出空间,这都会留下新的漏洞,无论这些块的大小有多大,并且“空闲块”的数量通常会增加......虽然如果两个或更多连续块被释放,“空闲块”的数量只会增加 1,如果新的 -释放的块与一个已经空闲的块是连续的——那个空闲块的大小变得更大了。查询缓存中任何打开的空闲内存块都计为 1 个空闲块。

    当然,一个小于 的空闲块query_cache_min_res_unit根本不会被使用。

    所以,查询缓存碎片。如果服务器想要缓存一个新查询并且没有足够大小的空闲块可以安排(该描述看似简单,因为底层算法很复杂),则必须修剪其他东西......那就是你的Qcache_lowmem_prunes. 有一个“最近最少使用”(LRU)算法来决定修剪什么。

    问一下为什么服务器不对内存进行碎片整理是明智的……但这没有意义。查询缓存在可能时会有所帮助,但它根本不是战略性的。您不想将处理时间(尤其是花费在全局锁上的时间)投入到不必要的维护任务上。

    服务器花时间重新排列——碎片整理——查询缓存中的内存会适得其反,因为缓存的结果是不断变化的,而缓存的重点是提高性能。

    全局锁是您不想使用过大查询缓存的一个很好的理由......服务器将在那里花费太多时间,因为查询等待轮到它们查看它们是否碰巧被缓存并且您的性能会受到影响.

    但qcache_free_blocks它本质上是自由空间碎片的一个指标。现在查询缓存中存在许多不连续的可用内存块。对于要插入缓存的新查询,必须有足够大的可用空间块来包含查询、其结果以及(有时)其表引用。如果没有,那么必须有别的东西……这就是你所看到的。再次注意,可用空间不一定必须是连续的(从我通过阅读源代码可以看出),但当出现碎片时,并不是每个洞都会被填满。

    但是对于给定的工作负载,碎片往往会随着时间的推移而趋于平稳,因为通常没有任何东西会像您预期的那样长时间保留在查询缓存中。

    这是因为,在某些方面,查询缓存非常简单。

    每当缓存查询引用的表中的数据发生更改时,涉及该表的所有查询都会从缓存中删除——即使更改不会影响缓存结果。如果表发生更改但没有更改,这甚至是正确的,例如回滚的 InnoDB 事务。引用该表的查询缓存条目已被清除。

    此外,在服务器实际解析查询之前,会检查每个传入查询的查询缓存。唯一会匹配的是另一个完全相同的查询,逐个字节。 SELECT * FROM my_table并且select * from my_table不是逐字节相同的,因此查询缓存没有意识到它们是相同的查询。

    FLUSH QUERY CACHE不会清空查询缓存。它对查询缓存进行碎片整理,这就是为什么Qcache_free_blocks变为“1”的原因。所有可用空间都已合并。

    RESET QUERY CACHE实际上刷新(清除所有内容)查询缓存。

    FLUSH STATUS清除计数器,但这不是您想要常规执行的操作,因为这会将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;
    

    总块数增加了 3,插入数增加了 1,缓存中的查询数增加了 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 ...是告诉服务器不要将结果存储在缓存中的指令。当缓存在后续执行中为您提供看似快速的响应时,它对于对查询的真实执行时间进行基准测试很有用。

    • 21

相关问题

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

  • 什么时候是使用 MariaDB 而不是 MySQL 的合适时机,为什么?

  • 组如何跟踪数据库架构更改?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    授予用户对所有表的访问权限

    • 5 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve