【问题标题】:Database memory and disk work assignation数据库内存和磁盘工作分配
【发布时间】:2015-11-10 18:09:05
【问题描述】:
我正在阅读有关索引和索引策略的电子书章节,其中许多方面我已经知道,但我坚持使用 InnoDB 中的聚集索引,这是引用:
集群对 I/O 密集型工作负载的改进最大。如果
数据适合内存访问它的顺序不
真的很重要,所以集群并没有带来太多好处。
我相信这是事实,但我应该如何猜测数据是否适合内存?数据库如何决定何时处理内存中的数据,何时不处理?
假设我们有一个表 Emp,其中 ID、Name 和 Phone 列填充了 100 000记录
如果,例如,我将聚集索引放在 ID 列上,并执行此查询
SELECT * FROM Employee;
我如何知道这是否会利用聚集索引带来的好处?
它在某种程度上与这个线程有关
Difference between In memory databases and disk memory database
但我不确定数据库的行为方式
【问题讨论】:
标签:
mysql
memory-management
innodb
clustered-index
【解决方案1】:
您的示例可能是 20MB。
“在内存中”真正的意思是“在 InnoDB 缓冲池中”,其大小由innodb_buffer_pool_size 控制,应该设置为 可用 RAM 的 70% 左右。
如果您的查询命中磁盘而不是在 buffer_pool 中找到所有缓存,它将运行(这只是一个经验法则)慢 10 倍。
您在“聚集索引”上所说的内容具有误导性。让我扭转局面……
- InnoDB 确实需要
PRIMARY KEY。
- PK 是(根据 MySQL 中的定义)
UNIQUE。
- 一个表只能有一个 PK。
- PK 可以是一个“自然”键,由一个(或多个)“自然”工作的列组成。
- 如果您没有“自然”的选择,请使用
id INT UNSIGNED NOT NULL AUTO_INCREMENT。
- PK 和数据存储在同一个 BTree 中。 (实际上是一个 B+Tree。)这导致“PK 与数据聚集在一起”。
真正的问题不是某个东西是否集群,而是它是否缓存在 RAM 中。 (记住 10 倍 RoT。)
- 如果表很小,它将保留在缓存中(一旦所有块都被触及),从而避免磁盘命中。
- 如果一个大表的某个子集是“热的”,它往往会留在缓存中。
- 如果您必须“随机”访问一个巨大的表,您将因大量磁盘命中而导致速度变慢。 (当将 UUID 用作
PRIMARY KEY 或 其他类型的 INDEX 时,会发生这种情况。)
数据库如何决定何时处理内存中的数据,何时不处理?
那也是“错误的”。所有处理都在内存中。在逐块的基础上,表和索引的片段被移入/移出 buffer_pool。一个块(在 InnoDB 中)是 16KB。而buffer_pool就是这些块的“缓存”。
SELECT * FROM Employee;
很简单,但成本很高。它是这样运行的:
- “打开”表
Employee(如果尚未打开——不同的“缓存”会处理此问题)。
- 转到表格的开头。这涉及向下钻取 PK 的 BTree 的左侧到第一个叶节点(块)。如果尚未缓存,则将其提取到 buffer_pool 中。
- 读取一行 -- 这将在该叶节点中。
- 阅读下一行——这可能在同一块中。如果没有,则获取“下一个”块(必要时从磁盘读取)。
- 重复第 4 步,直到完成表格。
如果你有一个WHERE 子句,事情会变得更有趣。然后就看是PK还是其他INDEX了。
等等等等