%的RAM. 如果内存很大,并使用 5.5(及以上)版本,可以考虑使用 多个缓存池. 推荐设置 1 - 16 个 innodb_buffer_pool_instances, 每个都不小于1 GB. (很抱歉,没有最优设置为多少个的具体参考指标;但应该不能设置太多). 与此同时,设置 key_buffer_size = 20M(很小,但不是零)
如果你在数据库中混合使用多个引擎,将两个值都降低一些.
最大连接数,线程栈
(max_connections,thread_stack)
每个“线程”都要占用一定的内存. 通常为 200 KB左右; 因此 100个线程大概就是 20 MB. 如果设置 max_connections = 1000,那大概就需要 200 MB,或者更多. 同时连接数太大可能会引起其他某些问题,这点需要注意.
在5.6(或 MariaDB5.5)中,可以选择线程池与 max_connections 交互. 这是一个高级话题.
线程栈溢出很少出现. 如果确实发生了,可以设置: thread_stack = 256K
点击查看更多关于max_connections, wait_timeout,连接池的讨论
table_cache(table_open_cache)
(某些版本中名字不一样).
操作系统对单个进程能打开的文件数有限制. 打开每个表需要 1-3个文件. 每个表分区(PARTITION)等价于一个表. 在分区表上的多数操作都会打开所有的分区.
在 *nix中, ulimit 显示文件限制是多少. 最大值一般是上万,但有可能被设置为 1024. 这就限制了只能打开300个左右的表. 更多关于ulimit的讨论请点击这里(这一段是有争议的.) 另一方面,表缓存(过去 )的实现方式很低效 —— 查找通过线性扫描来完成. 因此,设置 table_cache 为几千确实会使得 mysql变慢. (基准测试也证明了这一点.)
你可以通过 SHOW GLOBAL STATUS; 查看系统的性能信息, 并计算 每秒打开数(opens/second): Opened_files /Uptime , 如果这个值较大,例如大于 5, 那么应该加大 table_cache; 如果很小,比如是 1,通过减小 table_cache 值,可能会对性能有所改善.
查询缓存(Query Cache)
简短的回答: 设置 query_cache_type = OFF 及 query_cache_size = 0
QC(Query Cache)实际上是将 SELECT语句与结果集(resultsets)进行散列映射.
详细的回答…… 关于“查询缓存”有许多种观点; 其中许多是负面的.
新手警告! QC与key_buffer和buffer_pool完全无关. 当命中时, QC速度快如闪电. 要创建一个运行快1000倍的基准测试并不难. 在QC中只有一个互斥锁(译者注: 锁越少,就是锁钥匙越少,高并发时就会激烈竞争/等待). 除非将QC设置为OFF与0,否则每次查询都会去对比一遍.真相,互斥锁会发生碰撞,即使 query_cache_type = DEMAND (2).真相,互斥锁会发生碰撞,即便设置了 SQL_NO_CACHE.查询语句只要变了一点点(即使多了个空格)都可能导致在QC中生成多个不同的缓存项. “修改”是代价高昂与频繁的:
在一个表中发生任何 write 事件, QC中对应到这个表的所有条目都会被清除. 即便在只读从服务器(readonly Slave)上也是这样.清除使用的是线性算法来执行,所以QC较大(比如200MB)则会导致速度明显地变慢. 要查看QC的执行效率如何,执行 SHOW GLOBAL STATUS LIKE 'Qc%'; 然后计算read的命中率: Qcache_hits / Qcache_inserts, 如果大于5,则 QC的效率还不错.
如果QC适合你的应用,那么我推荐:
query_cache_size = 不超过50M query_cache_type = DEMAND 在所有 SELECT 语句中指明 SQL_CACHE 或 SQL_NO_CACHE, 根据哪些查询可能会从QC缓存中命中. 深入了解Query Cache
thread_cache_size
这是一个很小的调优项. 设置为 0 会降低线程(连接)创建的速度. 设置为较小的值(比如 10) 是比较好的. 该选项对RAM没有多少影响.
它是服务器额外保持的线程数量,不会影响实际线程数; 起限制作用的是 max_connections.
二进制日志
如果为 复制(replication) 或 时间点恢复(point-in-time recovery) 启用二进制日志(通过 og_bin开启), 则服务器将一直记录二进制日志(binary logs). 也就是说,可能慢慢地占用磁盘. 建议设置 expire_logs_days = 14 ,只保留14天的日志记录.
swappiness
RHEL,非常英明地,允许用户自己控制 OS 如何进行预先内存交换分配. 总的来说这是很好的策略,但对MySQL来说则是一个灾难.
(感觉翻译的有点不流畅,本段原文为: RHEL, in its infinite wisdom, decided to let you control how aggressively the OS will preemptively swap RAM. This is good in general, but lousy for MySQL)
MySQL期望相当稳定的内存分配 —— 缓存(大部分)是预先分配的; 线程(大都)是限制数量的. 任何内存交换都可能极大地损害MySQL的性能.
设置很高的swappiness值,会丢失一些内存,因为操作系统试图为以后的分配保留大量的自由空间(MySQL一般是不需要的).
设置swappiness = 0,不交换,在内存不足时操作系统可能会崩溃,. 我宁愿MySQL一卡一卡的,也不希望他崩了.
对于MySQL-only(专用)服务器, 中间数(比如5 )可能是一个很好的值.
NUMA
OK,是时候了解一些CPU管理内存的架构了. 我们先看 NUMA(Non-Uniform Memory Access, 非统一内存寻址). 每个CPU(或多路服务器中的每个socket(CPU插座)) 都挂载有一部分内存. 这使得访问本地(local) RAM 非常快, 而访问挂载在其他 CPU下的RAM要慢上数十个周期.
接着看操作系统. 在(RHEL )很多情形下,有两个行为:
OS分配的内存固定到 “first(第一个)” CPU名下. 接着分配的其他内存也默认分配到第一个CPU名下,直到它满了. 现在问题来了.
OS与MySQL分配完了第一个 CPU的所有RAM. MySQL分配了第二个 CPU的部分内存. 操作系统OS还需要分配一些其他内存. Ouch —— 一个CPU需要分配内存,但自己名下控制的RAM已经耗尽了,所以它将MySQL的部分内存置换出去. 渣渣!
可能的解决方案:配置BIOS内存分配为 “interleave”(交错). 这将防止过早交换(premature swapping),代价是有一半左右的 RAM 访问要跨CPU(off-CPU). 嗯,不论如何访问的代价都较大, 如果真的要使用所有内存的话.
整体性能损失/收益:几个百分点.
大内存分页(huge pages)
这里有另一个硬件性能陷阱.
CPU访问RAM,特别是将64位地址映射到某个地方, 比如 128 GB 或“真实”的RAM,会使用TL