我有以下场景:在MySQL数据库中,我有2个MyISAM表,一个有420万行,另一个有3.2亿行。以下是表格的架构:
表1(4.2M行)
F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY
f2 varchar(40)
f3 varchar(40)
f4 varchar(40)
f5 varchar(40)
f6 smallint(6)
f7 smallint(6)
f8 varchar(40)
f9 varchar(40)
f10 smallint(6)
f11 varchar(10)
f12 tinyint(4)
f13 smallint(6)
f14 text
表2(320M行)
F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY
f2 INTEGER UNSIGNED NOT NULL
Table2位于不同的数据库中,但我使用的是一个查询这两个表的存储过程。两个表之间的关系是Table1.F1可能最多约。 Table2.F1(外键)中的100行匹配,并且将为这些匹配的键返回Table2.f2的值。 我在表1中有一个索引IX1(f2(15),f3(10)),在表2中有一个索引IX2(F1,f2)和IX3(f2)
我正在运行的查询如下:
SELECT g.F1
FROM DB1.Table1 g
INNER JOIN DB2.Table2 gp ON g.F1 = gp.F1
WHERE (gp.f2 = 452677825) AND
(g.f2 = 'A string value') LIMIT 0,56
此查询有时非常快(<1s),但更改g.F2所比较的字符串值会导致查询甚至超过11秒甚至30秒。我不明白为什么会这样。以下是执行SELECT的EXPLAIN输出。
1, 'SIMPLE', 'g', 'ref', 'PRIMARY,IX1', 'IX1', '17', 'const', 901, 'Using where'
1, 'SIMPLE', 'gp', 'ref', 'IX3,IX2', 'IX2', '8', 'DB1.g.F1,const', 1, 'Using index'
这似乎是一个非常好的执行计划。解释的顶行中的行数最多为2000,但我不明白为什么这应该花费不到几分之一秒才能返回结果。我还在查询上运行了探查器,发现查询在“发送数据”阶段花费了99.9%的时间。任何人都可以解释为什么会这样,以及如何优化查询?
提前致谢, 添
答案 0 :(得分:1)
我不是这方面的专家,但这里有一些想法:
g.F2
更改时查询速度更长是因为缓存。 MySQL将保存每个查询的结果(直到缓存已满),但新查询在空缓存上运行,因此它们需要更长时间。你不应该基于此进行优化。 (见How to measure accurately)
我无法从您的信息中了解g
或gp
表在gp
子句中是否具有更高的特异性(似乎where
?),但您可以想要尝试子查询。 (见How to force the inner query to execute first)
关于性能分析,你可能会达到一个物理阈值,比如超出ram分配(使用交换对于性能而言是灾难性的),这在explain
中是不明显的,或者explain
是否是错误的这种情况。
答案 1 :(得分:0)
如果您可以尝试调整my.cnf,则要使用的属性为key_buffer_size。 MyISAM索引存储在.MYI文件中,如果找到这些索引并总计文件大小(例如ls -lh /var/lib/mysql/dbname/*.MYI),您可以粗略估计密钥缓冲区需要适合的大小所有索引都在。默认情况下,MySQL文档建议不要超过系统内存的25%。
答案 2 :(得分:0)
两个表之间的关系是Table1.F1可能最多约为。 Table2.F1
中有100行
澄清一下,Table1.F1
和Table2.F1
之间的关系是一对一,还是一对多?对我来说,这个陈述暗示了一对多,但是从模式来看,每个字段都是主要的(即唯一的)密钥。
无论如何,我怀疑g.f2(15)
的制服不均匀,并且当统计异常值被击中时,性能会相应降低。
执行
的结果SELECT f2(15) AS f2_15, COUNT(*) AS cnt
FROM Table1
GROUP BY f2(15)
ORDER BY cnt DESC
显示一些重要的异常值?