MyISAM' SELECT ... WHERE IN'对于~10M行表和100个并发连接(每个查询返回~50K行),查询非常慢

时间:2017-02-21 13:11:24

标签: mysql myisam

我有一个大约10M行的MyISAM表。对于单个' SELECT ... WHERE IN'查询(约5000个值)需要~0.05s来获得~50K行。但是,当执行100个并发类似查询时,时间上升到~18秒。这对我没有意义,因为我在内存中有所有索引,并且返回的数据量不是很大(~500Kb)。有什么想法可以让这么慢吗?谢谢。

CREATE TABLE data (
  A bigint(20) UNSIGNED NOT NULL, 
  B int(10) UNSIGNED NOT NULL, 
  C smallint(5) UNSIGNED NOT NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

ALTER TABLE data ADD KEY A_key (A);

使用过的查询:

SELECT * FROM data WHERE A IN (VAL1, VAL2, ...);

2 个答案:

答案 0 :(得分:0)

你没有说你正在使用存储过程,所以我会从那里开始。编译存储过程,这意味着它应该利用查询执行计划的“缓存”。由于该计划是针对内存数据的,因此您可以获得更多性能。

即使计划缓存differs from server-to-server,您仍然可以利用程序来提高性能。例如。您可以为最常见的查询创建多个过程。虽然:这通常需要应用程序/客户端更改才能使用这些过程。我从未尝试过使用单个proc检查查询参数范围,然后使用case调用其中一个静态查询。

答案 1 :(得分:0)

50ms内的5000行也不错 - 可能大部分时间都是将数据泄露到网络上。

假设这正是架构的样子,让我解释一下MyISAM 中发生的事情。 (并非所有这些都适用于您应迁移到的InnoDB。)

INDEX(A)表现在成对的BTree中:[A,记录号]。对于每个5000 A值,向下钻取BTree。 (对于10M行表,BTree将大约4级。)BTree是1KB块并缓存在key_buffer中。 key_buffer_size的价值是多少?你有多少RAM? SHOW TABLE STATUS说什么? (我想用它来确定是否应该调整大小。)

找到记录号后,它会在.MYD文件中“搜索”以查找记录,读取它(15个字节)并将其发送出去。操作系统会缓存这些块,而不是MySQL。

这是几千个可能缓存的磁盘读取。 50ms是足够的时间只做大约5个旋转磁盘读取,所以我会说,由于两个缓存,大多数(如果不是全部)读取被避免。

100个并发线程...我假设每个线程都读取50行?让我列出瓶颈:

  • 100对1连接旋转。
  • 100个线程与1争夺CPU
  • 100个主题vs 1争夺key_buffer
  • 100个线程与1争用OS缓存
  • 100个线程与1个争用查询缓存的争用(如果你打开了这个;这是关闭它的理由)
  • MyISAM的最新重大改进是在单核机器时代。同时,InnoDB在正确处理多线程方面取得了很大进展。 (即使是最新版本,仍然只有100个。)(MyISAM已从MySQL 8.0中删除。)