当前位置: 首页 > 知识库问答 >
问题:

添加条件后严重的MySQL查询性能问题

谭嘉容
2023-03-14

我的问题是,我有一个mysql查询运行得非常快(0.3秒),尽管它有大量的左联接和联接列上的一些条件,但当我再添加一个条件时,查询需要花费180秒以上!我理解,条件意味着执行计划必须调整,首先拉出所有潜在的记录,然后在循环中应用条件,但对我来说奇怪的是,没有附加条件的快速查询只返回16行,即使只是用外部查询上的条件包装查询也要花费大量的时间,而您认为它只会添加一个通过16行的附加循环。

如果重要的话,这就是使用Amazon Aurora无服务器,它应该与MySQL5.7一致

下面是查询的样子。可以看到附加条件被注释掉了。(数据库本身的通用表结构目前无法更改,因此请不要建议进行完整的数据库重组)

select 
    e1.entityId as _id,
    v1.Value,
    v2.Value
    v3.Value,
    v4.Value,
    v5.Value,
    v6.Value,
    v7.Value,
    v8.Value,
    v9.Value,
    v10.Value,
    v11.Value,
    v12.Value 
from entity e1
left join val as v1 on (v1.entityId = e1.entityId and v1.attributeId = 1189) 
left join val as v2 on (v2.entityId = e1.entityId and v2.attributeId = 1190) 

left join entity as e2 on e2.entityId = (select entityId from entity where code = v1.Value and type = 88 limit 1) 
left join val as v3 on (v3.entityId = e2.entityId and v3.attributeId = 507) 
left join val as v4 on (v4.entityId = e2.entityId and v4.attributeId = 522) 
left join val as v5 on (v5.entityId = e2.entityId and v5.attributeId = 558)
left join val as v6 on (v6.entityId = e2.entityId and v6.attributeId = 516)
left join val as v7 on (v7.entityId = e2.entityId and v7.attributeId = 518)
left join val as v8 on (v8.entityId = e2.entityId and v8.attributeId = 1384) 
left join val as v9 on (v9.entityId = e2.entityId and v9.attributeId = 659) 
left join val as v10 on (v10.entityId = e2.entityId and v10.attributeId = 519) 
left join val as v11 on (v11.entityId = e2.entityId and v11.attributeId = 1614)

left join entity as e3 on e3.entityId = (select entityId from entity where code = v9.Value and type = 97 limit 1) 
left join val as v12 on (v12.entityId = e3.entityId and v12.attributeId = 661)

where e1.type = 154
and v2.Value = 'foo'
and v5.Value = 'bar'
and v10.Value = 'foo2'
-- and v11`.Value = 'bar2'

order by v3.Value asc;

把它包在这样的东西里还需要很长时间...

select * 
from (
    <query from above>
) sub
where sub.v11 = 'bar2';

我将在“实体”表上摆弄索引来改进执行计划,不管这可能会有什么帮助...但是,有人能解释一下这里发生了什么,我应该在执行计划中看到什么,这会显示出如此糟糕的表现吗?为什么将快速查询包装在子查询中,使外部查询只能循环16行需要很长的时间呢?

编辑:我注意到在慢速查询中,最左边的执行使用的是“68e9145e-43eb-4581-9727-4212be41bef5”(v11)的非唯一键查找(在val.entityId上),而不是其他执行使用的唯一键查找(在entityId和attributeId上的复合索引)。我想这可能是问题的一部分,但为什么它不能像其他地方一样使用综合指数呢?

PS:现在,由于我们知道结果集很小,我们将在nodeJS服务器中的结果集上使用过滤器实现最后一个条件服务器端。

下面是“show CREATE TABLE entity”和“show CREATE TABLE val”的结果。

CREATE TABLE `entity` (
  `entityId` int(11) NOT NULL AUTO_INCREMENT,
  `UID` varchar(64) NOT NULL,
  `type` int(11) NOT NULL,
  `code` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
  PRIMARY KEY (`entityId`),
  UNIQUE KEY `UID` (`UID`),
  KEY `IX_Entity_Type` (`type`),
  CONSTRAINT `FK_Entities_Types` FOREIGN KEY (`type`) REFERENCES `entityTypes` (`typeId`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=296138 DEFAULT CHARSET=latin1


CREATE TABLE `val` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `UID` varchar(64) NOT NULL,
  `attributeId` int(11) NOT NULL,
  `entityId` int(11) NOT NULL,
  `Value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
  PRIMARY KEY (`id`),
  UNIQUE KEY `UID` (`UID`),
  UNIQUE KEY `idx_val_entityId_attributeId` (`entityId`,`attributeId`),
  KEY `IX_val_attributeId` (`attributeId`),
  KEY `IX_val_entityId` (`entityId`)
) ENGINE=InnoDB AUTO_INCREMENT=2325375 DEFAULT CHARSET=latin1

共有1个答案

邓声
2023-03-14

请提供show CREATE table

我希望看到这些综合指数:

`val`: (entityId, attributeId)   -- order is not critical

唉,因为codelongtext,所以对于entity:index(type,code,entityId)是不可能的。因此,这将不是很有效:

        SELECT  entityId
            from  entity
            where  code = v9.Value
              and  type = 97
            limit  1

我看到limit有一个order by--您关心您得到的是哪个值吗?

也许这样写更好

    WHERE EXISTS ( SELECT 1 FROM entity
                WHERE entityID = e3.entityID
                  AND code     = v9.Value
                  AND type = 97 )

(您确定E3V9的混合使用吗?)

正在包装...

这将强制左联接变为联接。并且它摆脱了当时内部的顺序

那么优化器可能会决定最好从68E9145E-43EB-4581-9727-4212BE41BEF5开始,我将其称为VAL AS V11:

JOIN val AS v11 ON (v11.entityId = e2.id
             and  v11.attributeId = 1614)
             AND  v11.Value = 'bar2')

如果这是一个EAV表,那么它所做的就是验证[,1514]是否具有值'bar2'。这似乎不是一个明智的测试。

除了我以前的建议。

我更喜欢解释选择...

EAV

假设val是一个传统的EAV表,这可能会好得多:

CREATE TABLE `val` (
  `attributeId` int(11) NOT NULL,
  `entityId` int(11) NOT NULL,
  `Value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
  PRIMARY KEY(`entityId`,`attributeId`),
  KEY `IX_val_attributeId` (`attributeId`),
) ENGINE=InnoDB AUTO_INCREMENT=2325375 DEFAULT CHARSET=latin1

这两个ID没有实际用途(除非我遗漏了什么)。如果你因为一个框架而被迫使用它们,那是不幸的。将(entityId,attributeId)提升为PK使获取value的速度更快。

没有任何有用的方法可以在任何索引中包含longtext,因此我前面的一些建议需要更改。

 类似资料:
  • 我有5个SQL表 存储 工作人员 部门 SOLD_Items staff_rating 我创建了一个视图,将这四个表连接在一起。最后一个表(staff_rating),我希望在接近项目被出售的时间(sold_items.date)获得视图行的rating列。我尝试了以下SQL查询,这些查询工作正常,但存在性能问题。 SQL查询1 SQL查询2 SQL查询%2比SQL查询%1快。但这两种方法都存在性

  • 问题内容: 有人愿意帮助我吗?在具有10000行的MEMORY表上,以下查询大约需要18秒。如果我没有“ where”约束,则只需不到一分钟的时间。我已经打开查询缓存以及将其作为准备好的语句来尝试。有什么我可以做的吗?索引还是什么? 问题答案: 我认为这将为您提供所需的信息,而不管您关注的滚动日期范围…我已经通过创建带有两个标识列的自己的“发票”表进行了测试。使用@mySQL变量实际上非常简单,可

  • 主要内容:单一条件的查询语句,多条件的查询语句在 MySQL 中,如果需要有条件的从数据表中查询数据,可以使用 WHERE 关键字来指定查询条件。 使用 WHERE 关键字的语法格式如下: WHERE 查询条件 查询条件可以是: 带比较运算符和逻辑运算符的查询条件 带 BETWEEN AND 关键字的查询条件 带 IS NULL 关键字的查询条件 带 IN 关键字的查询条件 带 LIKE 关键字的查询条件 单一条件的查询语句 单一条件指的是在

  • 1)使用的第一个查询...大约用了23秒 目前我修改了查询..这需要大约9秒 我不确定要做的表演是什么?我希望这个查询是快速的..我尝试索引rid和id,但这仍然使查询变得更糟。 下面是表格的详细信息 mza_movie_upload MZA_Movie_Statics

  • 我在术语查询中要求弹性搜索中的嵌套字段,其中嵌套字段值应与术语查询中提供的值的数量完全匹配。例如,考虑下面的查询,在这里我们对名为类型的嵌套字段进行查询。 GET资产/_search 索引映射 样本文件: 上述查询应返回字段类型正好有2个值的文档,即“VOD”

  • 查询条件: {a:1,b:undefined}, {a:1,b:null}, mongodb查询,会忽略上述b字段吗?