Mysql 使用外键进行内部连接要比不使用外键慢得多

Mysql 使用外键进行内部连接要比不使用外键慢得多,mysql,mariadb,Mysql,Mariadb,请帮帮我,我被MariaDB服务器的奇怪行为所困扰。 我有三张桌子 创建表“默认工作”( `add_date`datetime(6)不为空, `id`int(11)非空自动增量, `title`varchar(255)不为空, `关键字`varchar(255)默认为空, `短文本`长文本默认为空, `下载`int(10)unsigned NOT NULL, `已发布的'tinyint(1)不为空, `subject_id`int(11)不为空, `工作类型id`int(11)不为空, 主键(`

请帮帮我,我被MariaDB服务器的奇怪行为所困扰。 我有三张桌子

创建表“默认工作”(
`add_date`datetime(6)不为空,
`id`int(11)非空自动增量,
`title`varchar(255)不为空,
`关键字`varchar(255)默认为空,
`短文本`长文本默认为空,
`下载`int(10)unsigned NOT NULL,
`已发布的'tinyint(1)不为空,
`subject_id`int(11)不为空,
`工作类型id`int(11)不为空,
主键(`id`),
使用BTREE键'default\u work\u subject\u id\u IDX'('subject\u id`),
使用BTREE键“default\u work\u work\u type\u id\u IDX”(“work\u type\u id”),
约束`default\u work\u FK`外键(`subject\u id`)引用`default\u subject`(`id`),
约束`default\u work\u FK\u 1`外键(`work\u type\u id`)引用`default\u worktype`(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=210673默认字符集=utf8
创建表“默认主题”(
`id`int(11)非空自动增量,
`subject`varchar(255)不为空,
`old_id`int(10)无符号非空,
`subject_literal`varchar(255)不为空,
主键(`id`)
)引擎=InnoDB自动增量=43默认字符集=utf8
创建表“默认工作类型”(
`id`int(11)非空自动增量,
`工作类型'varchar(250)不为空,
`description`longtext默认值为空,
`old_id`int(10)无符号非空,
`work_type_literal`varchar(250)不为空,
`title`varchar(255)不为空,
`多个'varchar(255)不为空,
`关键字`varchar(255)不为空,
主键(`id`),
唯一键“default\u worktype\u old\u id\u a8b508fe\u uniq”(“old\u id”),
唯一键'default\u worktype\u work\u type\u literal\u 1e609434\u uniq'('work\u type\u literal`)
)ENGINE=InnoDB自动增量=13默认字符集=utf8
这些表是由Django ORM创建的,但看起来还可以。 default\u work表有大约200000条记录,default\u subject-42条,以及default\u worktype-12条

在Django admin中通过这些表之间的简单连接发出请求之后,我有大约9秒的查询时间。 我在SQL日志中找到了一个原始查询:

选择'default\u work`.'id`、'default\u work`.'title`、'default\u worktype`.'work\u type`、'default\u subject`.'subject``
从“默认”到“工作”`
内部联接'default'u subject'ON('default'u work`.'subject'id`='default'u subject`.'id`)
上的内部联接'default\u worktype'('default\u work`.'work\u type\u id`='default\u worktype`.'id`)
按“默认工作”排序。`id`DESC LIMIT 100
说明如下:

这有点令人困惑,因为当我删除表default\u work上除主键之外的所有索引时,结果完全不同。请求时间约为3.4毫秒,解释显示所有主键都使用正确。


另外,我试图在PostgreSQL上重现这种情况,但得到了1.3毫秒的索引和外键请求。

查看您的解释结果,您可以看到当打开外键时,系统在联接中使用该键,而不是选择在目标表中使用主键。(第2行)

由于将有许多具有相同值的记录,因此会大量增加正在评估的记录


我不知道它为什么选择这样做。您可能会发现,以不同的顺序重写select语句将改变它选择索引的方式。如果在ON子句中先将目标表加密,然后再将源表加密,您可能会发现选择不同(
default\u subject
id
=
default\u work
subject\u id

查看EXPLAIN结果,您可以看到当打开外键时,系统正在联接中使用该键,而不是选择使用目标表中的主键。(第2行)

由于将有许多具有相同值的记录,因此会大量增加正在评估的记录


我不知道它为什么选择这样做。您可能会发现,以不同的顺序重写select语句将改变它选择索引的方式。如果在ON子句中先加密目标表,然后加密源表(
default\u subject
id
=
default\u work
subject\u id
),您可能会发现选择不同。

那么SQL Server在这里做什么呢?有关系吗?请不要标记不相关的标记。抱歉,键入错误。删除。这听起来像是优化器在决定查询计划时未能使用
LIMIT
的一个很好的例子。请向jira.mariadb.com提交一个bug。那么SQL Server在这里做什么?有关系吗?请不要标记不相关的标记。抱歉,键入错误。删除。这听起来像是优化器在决定查询计划时未能使用
LIMIT
的一个很好的例子。请向jira.mariadb.com提交一个bug谢谢,但我不明白为什么MySql不像PostgresSQL那样使用主键。对比一下PgSQL和MySQL,我觉得是时候改变我最喜欢的DB引擎了。不,我也不知道它为什么选择这么做。好的一面是,尽管看起来人类的思维仍然是必需的!谢谢,但我不明白为什么MySql不像PostgresSQL那样使用主键。对比一下PgSQL和MySQL,我觉得是时候改变我最喜欢的DB引擎了。不,我也不知道它为什么选择这么做。好的一面是,尽管看起来人类的思维仍然是必需的!