Kry*_*ble 5 mysql index optimization
我对 mysql 优化和例程有一些经验,但最近有一些事情吸引了我。
我在 ec2 实例上使用本地 mysql 安装,然后刚刚迁移到 RDS,这样我就可以高枕无忧了。
问题是我的应用程序存在一些遗留问题,之前在 mysql 5.1 上运行,现在在 mysql 5.6 上运行。
我们的数据库是建立在index_merge将被mysql使用的前提下的,所以我们的索引不是复合的;它们都会影响单列;我知道这可能有多糟糕,也知道它有多糟糕,但到目前为止它运行良好;我现在无法真正更改它,因为我们有 300 多张桌子。
让我陷入麻烦的是我的一张桌子控制着库存。该表具有以下结构:
id (PK)
companyId (btree index)
productId (btree index)
transactionType (input, output or stock balance; btree index)
transactionDate (btree index)
transactionPrice
Run Code Online (Sandbox Code Playgroud)
以及其他一些并不重要的专栏。
当我运行选择查询来获取给定产品的最后价格时,如下所示:
SELECT
transactionPrice
FROM
stock
WHERE
productId = x
AND transactionType = 'input'
AND companyId = y
AND transactionDate < '2017-07-07'
ORDER BY transactionDate DESC
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
我所期望的是 MySQL 会合并(很可能)非常具体的 ProductId 和 companyId 索引,并读取大约 4 行;但实际发生的情况是,MySQL 决定通过对 transactionDate 进行排序而不将其合并到任何其他索引来迭代超过 500 万行。
我决定进一步挖掘:
SHOW @@optimizer_switch显示 index_merge 标志全部打开IGNOREtransactionDate 索引;id 确实决定按预期索引合并productId 和companyId!ANALYZE TABLE,它仍然使用相同的行为所以我现在有点迷失了;什么变量可能会影响这个?如何帮助优化器鼓励使用索引合并而不是全表扫描?
Edit1:在 Rick 的回答后添加更多信息:
BUFFER POOL AND MEMORY
Total memory allocated 25738477568; in additional pool allocated 0
Dictionary memory allocated 12453955
Buffer pool size 1534976
Free buffers 8194
Database pages 1383533
Old database pages 510554
Modified db pages 4364
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 32361311, not young 319332363
1.87 youngs/s, 0.62 non-youngs/s
Pages read 15508690, created 745849, written 11868579
0.12 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 1383533, unzip_LRU len: 0
I/O sum[24]:cur[0], unzip sum[0]:cur[0]
正如您所看到的,我的缓冲池命中率为 1000 / 1000,这应该意味着它很好,对吧?
一些表格统计数据: - 1000 万条条目 - 约 75 万种产品 - 3 种交易类型 - 约 150 家公司
最后创建表如下:
CREATE TABLE `estoque` (
`id` int(11) NOT NULL DEFAULT '0',
`companyId` int(11) NOT NULL DEFAULT '0',
`productId` int(11) NOT NULL DEFAULT '0',
`transactionDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`transactionType` char(1) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `transactionType` (`transactionType`),
KEY `transactionDate` (`transactionDate`),
KEY `productId` (`productId`),
KEY `companyId` (`companyId`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Run Code Online (Sandbox Code Playgroud)
还有其他列,但为了清楚起见,我省略了它们。
多年来我发现MySQL很少使用索引合并。我认为部分原因是效率太低。为了执行它,它必须
即使可以使用索引合并,它本质上也保证比合适的复合索引慢。
对于有问题的查询,这个索引是最佳的,甚至可以处理ORDER BY(从而避免 tmp 和排序),我认为索引合并不能做到这一点:
INDEX(productId, transactionType, companyId, -- in any order
transactionDate) -- last
Run Code Online (Sandbox Code Playgroud)
关于相关主题...我认为这是一张非常大的桌子?buffer_pool 有多大?是 I/O 限制型还是完全缓存型?
我问这些是因为,如果它是 I/O 绑定的,则选择PRIMARY becomes important in performance. Would you care to show usSHOW CREATE TABLE`;我会进一步解释。根据您提供的信息,我猜测查询所需的行分散在表中,而不是“聚集”在几个块中。
更多有用的信息:有多少种不同的产品?transactionTypes - 显然是 3?公司?它们分布均匀吗?
| 归档时间: |
|
| 查看次数: |
1485 次 |
| 最近记录: |