我在mysqld中看到了一个我不理解的表现行为。
我有一个表t,主键id和三个数据列col1,... col4。
数据在4个TSV文件'col1.tsv',...'col4.tsv'中。我用来摄取它们的程序是:
CREATE TABLE t (
id INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
col4 CHAR(12) CHARACTER SET latin1 NOT NULL );
LOAD DATA LOCAL INFILE # POP 1
'col1.tsv' INTO TABLE t (id, col1);
ALTER TABLE t ADD PRIMARY KEY (id);
SET GLOBAL hot_keys.key_buffer_size= # something suitable
CACHE INDEX t IN hot_keys;
LOAD INDEX INTO CACHE t;
DROP TABLE IF EXISTS tmpt;
CREATE TABLE tmpt ( id INT NOT NULL, val INT NOT NULL );
LOAD DATA LOCAL INFILE 'col2.tsv' INTO TABLE tmpt tt;
INSERT INTO t (id, col2) # POP 2
SELECT tt.id, tt.val FROM tmpt tt
ON DUPLICATE KEY UPDATE col2=tt.val;
DROP TABLE IF EXISTS tmpt;
CREATE TABLE tmpt ( id INT NOT NULL, val INT NOT NULL );
LOAD DATA LOCAL INFILE 'col3.tsv' INTO TABLE tmpt tt;
INSERT INTO t (id, col3) # POP 3
SELECT tt.id, tt.val FROM tmpt tt
ON DUPLICATE KEY UPDATE col3=tt.val;
DROP TABLE IF EXISTS tmpt;
CREATE TABLE tmpt ( id INT NOT NULL,
val CHAR(12) CHARACTER SET latin1 NOT NULL );
LOAD DATA LOCAL INFILE 'col4.tsv' INTO TABLE tmpt tt;
INSERT INTO t (id, col4) # POP 4
SELECT tt.id, tt.val FROM tmpt tt
ON DUPLICATE KEY UPDATE col4=tt.val;
现在这是我不理解的表演。 POP有时候 和3 INSERT INTO ... SELECT ... ON DUPLICATE KEY UPDATE查询使用mysqld运行得非常快 占用100%的核心,在其他时候,mysqld陷入1%CPU读数t.MYD,即表t的MyISAM数据文件,随机偏移。
我很难隔离它在哪种情况下速度很快 它很慢但我找到了一个可重复的案例:
在上面的序列中,POP 2和3非常慢。但是如果我创造了 没有col4然后POP 2和POP 3非常快。为什么呢?
然后,如果之后,我使用ALTER TABLE查询添加col4,然后运行POP 4 也很快。
同样,当INSERT运行缓慢时,mysqld在文件IO中陷入困境 读取表t的MyISAM数据文件中的随机偏移量。我甚至没有 明白为什么要阅读该文件。
MySQL服务器版本5.0.87。 Core 2 Duo iMac上的OS X 10.6.4。
更新
我最终找到了(我认为是)这个问题的答案。一些插入缓慢而一些快速的神秘差异取决于数据。
线索是:当插入缓慢时,mysqld在t.MYD读取之间平均寻求0.5GB。当它很快时,连续读取具有微小的相对偏移。
由于某些'col?.tsv'文件的行与w.r.t大致相同,所以出现了混乱。 id
列,而其他列是相对于它们随机排序的。
在加载和插入tsv文件之前,我可以通过在tsv文件上使用sort(1)来大幅缩短整体处理时间。
答案 0 :(得分:0)
这是一个非常开放的问题......这是一个推测性的,开放的答案。 :)
...当INSERT运行缓慢时,mysqld在文件IO中陷入困境,从表t的MyISAM数据文件中的随机偏移读取。我甚至不明白为什么要阅读那个文件。
我可以想到两种可能的解释:
但如果我创建没有col4的t,那么POP 2和POP 3非常快。为什么呢?
如果它是一个固定行大小的MyISAM表,由于表中的数据类型,它看起来像是CHAR
字段,即使它是空白的,也会使磁盘上的表大75%(每个INT
字段4个字节= 16个字节,而CHAR(12)
将添加另外12个字节)。所以,理论上,你需要读/写75%以上。
您的数据集是否适合内存?您是否考虑过使用InnoDB或内存表?
附录
如果可用/活动/热数据集从内存中拟合到不适合内存,则性能降低数量级并非闻所未闻。一对夫妇读到:
http://jayant7k.blogspot.com/2010/10/foursquare-outage-post-mortem.html
http://www.mysqlperformanceblog.com/2010/11/19/is-there-benefit-from-having-more-memory/