我有一个非常大的数据库 (~150GB),其中包含许多不同大小的表。它运行在一个相对稳定的服务器上(16GB RAM,8 核 Xeon),无论如何都没有用到它的全部容量(通常是一半的 RAM 和 ~25% 的 CPU)。
但是随着数据库的增长,我遇到越来越多的查询极慢的问题,即使在:
- 它们看起来优化得很好(至少索引很好)
- 它们不生成文件排序或 tmp 表
- 他们不使用内存可能放不下的最大表格
它出现在各种查询中,但这里是一个有时需要超过 1000 万(!)的查询示例:
SELECT A.*, B.*, C.*
FROM A
INNER JOIN B USING(id)
LEFT OUTER JOIN C
ON (A.id=C.id AND C.date="2016-01-10")
WHERE A.field1 > 100
AND ( B.field2 REGEXP 'XX|YY'
OR B.field3 REGEXP 'XX|YY' )
表的大小和索引如下:
- A:25MB 带 INDEX(id)
- B : 60MB 带 INDEX(id)
- C : 600MB 带 INDEX(id,date)
好吧,这是对 B 的全表扫描,但只有 200k 行,而且表相对较小(至少它们可以放入内存)。索引似乎很好。那么世界上怎么可能需要超过 1000 万的处理时间呢?
另一个用了 10 多秒的更简单的例子:
SELECT * FROM messages WHERE user_id=1 ORDER BY date ASC
解释说:
select_type SIMPLE
table messages
type ref
possible_keys user_id
key user_id
key_len 8
ref const
rows 5157
Extra Using index condition; Using where
表 messages 大约 500MB,带有 INDEX(user_id, date)。
请注意,所有表都在使用 myIsam(但这里的问题不在于表锁)。
我怀疑是 mySql 配置不是最优的,阻止它使用空闲内存,从而使它使用磁盘访问,使一切变慢。它也发生在更简单的查询和更小的表中,这一事实似乎也暗示了配置问题。但这只是一个猜测,因为我看不出还有什么可以解释这一点。
另请注意,通常情况下,这些慢速查询在重新执行时(如果不是瞬时的)要快得多(我想是因为缓存)。它们的缓慢还取决于一天中的时刻(我注意到清晨的情况要糟糕得多),而资源永远不会用到满负荷。
有人知道哪里出了问题吗?
提前致谢!
最佳答案
我假设 id
是每个表中的 PRIMARY KEY
?
C
需要 INDEX(date, id)
-- 不 INDEX(date), INDEX( id)
.
A
需要 INDEX(field1)
(但它可能无济于事)
除非您确实需要所有列,否则不要使用 *
。
如果您不需要LEFT JOIN
,请使用JOIN
。这样我为 C
提供的索引可能更有用。
事实上,优化器决定对 B
进行全表扫描是唯一有用的开始方式。
请告诉我们REGEXPs
到底是什么;可能有改进它们的方法。
messages
需要 INDEX(user_id, date)
,按此顺序。请提供 SHOW CREATE TABLE
以便我们确认您已经拥有该 2 列复合索引。
改用 InnoDB 应该会有所帮助。
对于 MyISAM,key_buffer_size 应该设置为 可用 RAM 的大约 20%。 (如果你的索引总数(.MYI 文件)小于那个,你可以更低。)在你切换到 InnoDB 之前,innodb_buffer_pool_size
应该是 0。
如果重新执行“立即”运行,那么您正在使用查询缓存。让我们忽略它。但是不要让 query_cache_size
大于 50M。
早上比较慢?也许所有的缓存都是冷的。这可能是因为每晚重启或备份。
关于MySql - 极其缓慢的简单查询(错误的内存配置?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36527951/