我有一个非常大的数据库(~150GB),有许多不同大小的表。它运行在一台相对稳固的服务器上(16GB内存,8核Xeon),无论如何都不能满负荷运行(通常是RAM的一半,也是CPU的25%)。
但是随着数据库的增长,我越来越多的查询问题极其缓慢,即使在以下情况下:
它出现在各种查询中,但这是一个有时需要超过10mn(!)的查询示例:
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' )
表格大小&索引如下:
好吧,它是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
表消息大约为500MB,带有INDEX(user_id,date)。
请注意,所有表都使用myIsam(但此处的问题与表锁无关)。
我怀疑mySql配置不是最佳配置,并且阻止它使用空闲内存,从而使其使用磁盘访问,使一切变慢。事实上它甚至更简单的查询和&较小的表似乎暗示了配置问题。但这只是一个猜测,因为我没有看到还有什么可以解释这个。
另请注意,通常情况下,这些慢查询在重新执行时会更快(如果不是即时的)(因为我想象的缓存)。它们的缓慢还取决于当天的时刻(我注意到它在清晨更加糟糕),而资源从未用于满负荷。
有人知道会出现什么问题吗?
提前致谢!
答案 0 :(得分:0)
我认为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。
早上较慢?也许所有的缓存都很冷。这可能是因为每晚重启或备份。