我有一个大约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, ...);
答案 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行?让我列出瓶颈: