【发布时间】:2016-05-31 06:40:21
【问题描述】:
我有一个简单的键值存储表,有 85M 行,文件大小为 5GB。 (Wordpress 后元表。)
CREATE TABLE `wp_postmeta` (
`meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`post_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`meta_value` longtext COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`meta_id`),
KEY `post_id` (`post_id`),
KEY `meta_key` (`meta_key`(191)),
KEY `meta_value` (`meta_value`(100)),
KEY `meta_value_len_10` (`meta_value`(10)),
KEY `meta_value_len_1` (`meta_value`(1))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
当我运行以下查询时:
SELECT post_id
FROM wp_postmeta
WHERE meta_key = "case"
AND meta_value = "359976";
查找速度很快,不到 50 毫秒。它按预期使用 meta_value 索引,并且可以将扫描范围缩小到 4 行(如 EXPLAIN 中所示)。当我减少 meta_value 的目标值的位数时,行扫描可能会增加到几百,这仍然是微不足道的。
问题案例——查询运行非常慢(10 秒以上)的唯一情况——是目标值同时是一个字符长度和一个数值;基本上,如果它只是 0 到 9。然后,查询会扫描 400,000 行。如果我改用一个单字符的字母,则查询很好,这让我感到困惑。
问题案例:
SELECT post_id
FROM wp_postmeta
WHERE meta_key = "case"
AND meta_value = "5";
幕后的另一个区别是问题查询是唯一使用 meta_value_len_10 索引的类型。所有其他(包括个位数的 alpha)都使用原版 meta_value 索引。
即使我运行 FORCE INDEX(meta_key,meta_value_len_1) 来定位那个单个数字,也没有什么区别。我还尝试创建一个 4 个字符长的索引,但没有任何区别。
请注意,在任何情况下,EXPLAIN 始终显示“使用 where”作为查找方法。没有“使用文件排序”或任何指示磁盘 I/O 的内容(除了问题案例中的绝对行数)。
【问题讨论】:
-
性能问题应该包括
EXPLAIN ANALYZE和一些关于表大小、索引、当前时间性能、期望时间等的信息。Slow是一个相对术语,我们需要一个真实的值来比较。 MySQL -
谢谢,我添加了表大小和特定查询时间。我认为这是暗示,因为我在谈论正确的索引,我们都知道不想要的性能和想要的性能之间的速度差异可能是 5 到 10 倍。
-
这是帮助用户改进问题的通用注释。对于您的情况,最重要的是您没有为您的测试提供 EXPLAIN 结果。
-
键值模式糟糕的另一个原因。
-
@RickJames:这只是我们在使用 EAV 模型时体验到的那种快乐的一个小例子。
标签: mysql database indexing query-optimization