同一张桌子上有2个内部联接:第二个使它变慢

时间:2019-05-02 11:51:36

标签: mysql doctrine-extensions

我目前正在为Symfony 4应用程序进行数据库翻译,并使用Doctrine的Translatable扩展名(http://atlantic18.github.io/DoctrineExtensions/doc/translatable.html)。它使用以下结构为我的实体创建一个翻译表:

CREATE TABLE `equipment_translations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `locale` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  `object_class` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `field` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `foreign_key` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
  `content` longtext COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`id`),
  KEY `equipment_translation_idx` (`foreign_key`,`locale`,`field`),
) ENGINE=InnoDB AUTO_INCREMENT=5973 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

我有2个不同的字段必须翻译:{{1​​}}和name 两者的翻译都存储在同一张表中,并相应地设置了description值。

不幸的是,使用以下查询在两个连接上执行内部联接会导致性能很差:

field

这是一个自动生成的查询(最终结果由我的ORM实体中的学说合并),为此我删除了一些语句以使其更简单。

现在,如果我仅使用这些连接之一,则查询将花费0.01s:

SELECT *
FROM   equipment e5_ 
       INNER JOIN equipment_translations t6_ 
               ON t6_.foreign_key = e5_.id 
                  AND t6_.locale = 'en' 
                  AND t6_.field = 'name' 
        INNER JOIN equipment_translations t7_ 
               ON t7_.foreign_key = e5_.id 
                  AND t7_.locale = 'en' 
                  AND t7_.field = 'description' 
WHERE  e5_.engine = %ID%;

但是,使用两个联接时,要花费0.5s的时间。这已经很糟糕了,但是我有更复杂的查询,像这样花费数十秒(没有翻译连接,它们在毫秒范围内)...对于网站来说,这显然是不可接受的。

SQL EXPLAIN输出以下内容:

SELECT *
FROM   equipment e5_ 
       INNER JOIN equipment_translations t6_ 
               ON t6_.foreign_key = e5_.id 
                  AND t6_.locale = 'en' 
                  AND t6_.field = 'name' 
WHERE  e5_.engine = %ID%; 

然后我尝试使用+---+--------+-----+----+--------+--------------------------------+---------------------------+----+-------------------------+------+-------+-----------------------+----------------------------------------+ | 1 | SIMPLE | t6_ | \N | ref | equipment_translation_idx,idx2 | equipment_translation_idx | 34 | const | 2937 | 10.00 | Using index condition | | +---+--------+-----+----+--------+--------------------------------+---------------------------+----+-------------------------+------+-------+-----------------------+----------------------------------------+ | 1 | SIMPLE | e5_ | \N | eq_ref | PRIMARY,engine | PRIMARY | 4 | autopm2.t6_.foreign_key | 1 | 5.00 | Using where | | | 1 | SIMPLE | t7_ | \N | ALL | equipment_translation_idx,idx2 | \N | \N | \N | 5874 | 0.50 | Using where | Using join buffer (Block Nested Loop) | +---+--------+-----+----+--------+--------------------------------+---------------------------+----+-------------------------+------+-------+-----------------------+----------------------------------------+ ,它使MySQL实际上在第二个联接上使用索引,但是速度根本没有增加。

当然,如果我仅使用一个联接将两个FORCE INDEX FOR JOIN (equipment_translation_idx)联接在一起,查询速度很快,但是行数却翻倍,Doctrine无法将其合并到我的实体中。

所以我的问题是:为什么会发生这种情况,我对此可以采取任何措施,或者还有另一种方法可以使它快速运行吗?

经过测试的MySQL版本:5.7.22和5.5.62

0 个答案:

没有答案