我有一个巨大的(并且正在增长的)MyISAM表(700万行= 140Gb)。
CREATE TABLE `keypairs` (
`ID` char(60) NOT NULL,
`pair` char(60) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM
表格选项已更改为ROW_FORMAT=FIXED
,因为两列的长度始终固定为最大值(60)。是的,ID
很遗憾,而不是INT。
SELECT
查询速度效率非常好。
数据库和mysql引擎都是127.0.0.1/localhost
。 (没什么遥远的)
可悲的是,INSERT
很慢。我甚至没有谈到尝试LOAD DATA
数百万个新行......需要几天时间。
不会有任何并发读取。所有SELECT都是由我的本地服务器逐个完成的(不是供客户使用)
(适用于信息:文件大小.MYD = 88Gb,.MYI = 53Gb,.TMM = 400Mb)
答案 0 :(得分:2)
LOAD
之前对传入数据进行排序。这将提高PRIMARY KEY(id)
。PARTITIONing
不太可能有所帮助,除非ID
有一些有用的模式。PARTITIONing
将不帮助进行单行插入,也不会ID
进行单行抓取。CHAR
而不是VARCHAR
会浪费空间和速度。改变它。FIXED
只有在有很多“流失”的情况下才有用。 (删除+插入和/或更新)。.frm
是CREATE TABLE
的编码;这与此讨论无关。BINARY(16)
后需要16个字节。PRIMARY KEY
是BTree。如果ID
有点"随机",那么' next' ID(除非输入已排序)可能不会被缓存。不,BTree 不一直重新平衡。PRIMARY KEY
转换为辅助密钥(在添加AUTO_INCREMENT
之后)将不加快速度 - 它仍然需要使用{{1}更新BTree在它!ID
设置为大约70%的可用内存,但不大于{{1文件。我推荐一个大的key_buffer,因为那是随机访问的发生地; key_buffer_size
仅被附加到(假设您从未删除任何行)。.MYI
,以确保这些更改不会破坏其他地方的效果。.MYD
latin1或ascii; utf8会使用SELECTs
浪费更多空间。切换到InnoDB会使表的磁盘空间(数据+索引)增加一倍,可能增加三倍。因此,它可能会显示下来。但是一个缓解因素是PK已经集群化了#34;使用数据,因此您不会为插入的每一行更新两件事。请注意,CHARACTER SET
应降至10M,CHAR
应设置为可用内存的70%。
(我的子弹项目适用于InnoDB,除非指定了MyISAM。)
在使用InnoDB时,尝试每个事务插入1000行会很好。少于此会导致更多的交易开销;超过这导致超越撤消日志,导致不同形式的减速。
十六进制ID
由于key_buffer_size
始终为60个十六进制数字,因此请将其声明为innodb_buffer_pool_size
并通过ID
打包并通过BINARY(30)
获取。通过UNHEX(...)
进行测试。这将使数据缩小约25%,而MyISAM的PK缩小约40%。 (InnoDB总体上为25%。)
仅转换为HEX(ID)
:
WHERE ID = UNHEX(...)
微小内存
只有2GB的RAM,仅MyISAM数据集应使用BINARY(30)
和CREATE TABLE new (
ID BINARY(30) NOT NULL,
`pair` char(60) NOT NULL
-- adding the PK later is faster for MyISAM
) ENGINE=MyISAM;
INSERT INTO new
SELECT UNHEX(ID),
pair
FROM keypairs;
ALTER TABLE keypairs ADD
PRIMARY KEY (`ID`); -- For InnoDB, I would do differently
RENAME TABLE keypairs TO old,
new TO keypairs;
DROP TABLE old;
之类的内容。仅适用于InnoDB:key_buffer_size=300M
和innodb_buffer_pool_size=0
。由于key_buffer_size=10M
可能是某种摘要,因此非常随机。小缓存和随机密钥组合起来意味着几乎每个插入都涉及磁盘I / O.我的第一次估计更像是插入10M行30个小时。你有什么样的驱动器?如果您还没有固态硬盘,那么固态硬盘会有很大的不同。
加快innodb_buffer_pool_size=500M
的另一件事是在启动ID
之前按INSERTs
排序。但是ID
会变得棘手。这就是我推荐的内容。
LOAD
和UNHEX
创建 MyISAM 表tmp
,但无索引。 (不要担心ID BINARY(30)
;它不会被使用。)pair
将数据导入key_buffer_size
。LOAD
这将对表格进行排序。仍然没有索引。我认为,如果没有证据,这将是一个文件分区,通过密钥缓冲区"修复更快。对于这种情况。tmp
这会通过按ALTER TABLE tmp ORDER BY ID;
顺序将行提供到INSERT INTO keypairs SELECT * FROM tmp;
来最大化缓存。同样,我已经仔细拼写了一些内容,以便无论哪个引擎keypairs
都适用,它都能正常运行。我希望步骤3或4花费的时间最长,但我不知道哪一个。
答案 1 :(得分:0)
优化表格需要针对特定查询进行优化。除非您考虑到特定的问题,否则无法确定最佳优化策略。任何优化都会以牺牲其他类型的查询为代价来改进一种类型的查询。
例如,如果您的查询是SELECT SUM(pair) FROM keypairs
(无论如何都必须扫描整个表格的查询),分区不会有帮助,只会增加开销。
如果我们假设您的典型查询是通过其主键一次插入或选择一个密钥对,那么是的,分区可以帮助很多。这完全取决于优化器是否可以告诉您的查询将在一个狭窄的分区子集中找到它的数据(理想情况下是一个分区)。
还要确保调整MyISAM。没有很多调整选项:
key_buffer_size
以缓存索引。虽然我没有尝试过高于10GB的任何东西,但我无法保证MyISAM密钥缓冲区稳定在53GB(MYI文件的大小)。read_buffer_size
和read_rnd_buffer_size
。我无法在此处提供特定值,您应该使用查询测试不同的值。bulk_insert_buffer_size
大小调整为大小。它默认为8MB,我尝试至少256MB。我没有尝试过这种设置,所以我无法从经验中说话。我尽量不使用MyISAM。 MySQL绝对试图弃用它。
的回答...是否有自动命令ALTER TABLE添加INT ID增量列?
答案 2 :(得分:-1)
首先,您的主键不可递增。 这意味着,粗略地说:在每次插入时,索引都必须重新平衡。
难怪它在这么大的桌子上慢慢走。 而这样的引擎......
所以,对于第二个问题:保持MyISAM旧垃圾的重点是什么?
例如,在发生事故时,你不介意放松一两行(或十几岁)吗?等等,甚至抛弃当前的MySQL维护者(Oracle Corp)明确不鼓励使用MyISAM。
所以,这里有可能的解决方案:
1)切换到Inno;
2)如果你不能放弃char ID,那么:
添加自动增量数字键并将其设置为主数据 - 然后,将聚集索引并且插入成本会显着下降;
将当前密钥转换为二级索引;
3)如果你能 - 它很明显