mysql - 为什么内存表上的这个查询比 InnoDB 上的双胞胎要慢?

原文 标签 mysql performance memory innodb

我有一个表的 InnoDB 和 MEMORY 版本。两者都有相同的索引和相同的 30,000 行数据。当针对 MEMORY 表执行运行时,有一个特定的查询运行速度非常慢。

这是针对 InnoDB 的:

SELECT emails.id
FROM emails
LEFT JOIN custom_data_person pd1 ON (pd1.person_id = emails.person_id)
WHERE pd1.field_id = 13

2928 rows in set (0.24 sec)

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pd1
         type: ref
possible_keys: person_id,field_id
          key: field_id
      key_len: 5
          ref: const
         rows: 20240
        Extra: Using where; Using index
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: emails
         type: ref
possible_keys: person_id
          key: person_id
      key_len: 4
          ref: test.pd1.person_id
         rows: 1
        Extra: Using index

这是内存:
SELECT emails.id
FROM emails_memory AS emails
LEFT JOIN custom_data_person pd1 ON (pd1.person_id = emails.person_id)
WHERE pd1.field_id = 13

2928 rows in set (1.40 sec)

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emails
         type: ALL
possible_keys: person_id
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 30000
        Extra: 
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: pd1
         type: ref
possible_keys: person_id,field_id
          key: person_id
      key_len: 10
          ref: test.emails.person_id,const
         rows: 1
        Extra: Using where; Using index

(注意person_id索引是一个BTREE索引,我用默认的HASH索引也试过了,结果是一样的。)

因此,MySQL 似乎以不同的方式优化了第二个查询,这使其性能更差。这是为什么?我可以“修复”它吗?

最佳答案

你真的不在乎。对于一个有 30,000 行的小表,任何事情都会非常快,甚至是表扫描。

但是,看起来它选择了不同的解释计划。在 innodb 案例中,它首先使用了 custom_data_person 表,并使用了覆盖索引。然后它查询 emails 表中在 custom_data_person 表中找到的每一行。这似乎是理智的解释计划。

这可能是内存表优化器中的一些糟糕的悲观化。

我会避开内存表。如果您想要一个行为几乎像内存表的表,请使用 MyISAM 表并在服务器启动时截断它。内存表非常糟糕,因为它们存储填充到最大长度的 varchar,因此它们通常比其他类型的表使用更多的内存。 MyISAM 非常有效地使用存储。或者,对所有内容都使用 InnoDB 表。

不幸的是,innodb 没有提供在每个表的基础上设置持久性的方法,所以如果每个事务上的 fsync 困扰你,你必须做更大(因此更少)的事务。

使用多个引擎是一种折衷方案,因为服务器很少有任何方式可以在引擎之间自动划分其(有限)内存。所以你通常只想使用一个引擎;这包括内存引擎,如果您以这种方式配置它,它将很高兴地从您的 innodb 中取出大量内存(因此使其变慢,因为它可以在内存中容纳更少的数据库)。

不过说真的,你真的,真的,真的不在乎 30k 行。 30k 行可以容纳在最小的内存中,即使它们很大。当您使用 30k 行时,任何引擎都是内存引擎。

关于mysql - 为什么内存表上的这个查询比 InnoDB 上的双胞胎要慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4962797/

相关文章:

mysql - Binary(16)作为主键:Lightswitch可以识别GUID,但不能正确编写它们

php - 我的脚本中不断收到关于变量的错误

php - 优化sql语句以减少MySQL服务器负载

java - 我该如何写一个正确的路径来将文件保存在Java中?

python - 扁平大阵列的 Numpy 平均值比所有轴的平均值慢

c++ - 用 64 位替换 32 位循环计数器会在 Intel CPU 上使用 _mm_popcnt_u64 引入疯狂的性能偏差

mysql - 四舍五入的主日期时间键的MySQL改进

c# - 多少内存使用字节枚举,这是否优化了 C# 中的内存/速度?

linux - 了解 OOM 奇怪的行为?

c - 进程的虚拟地址空间的哪些部分是可覆盖的?