您的位置:首页 > 新闻 > 资讯 > 宣传片制作费用报价表_广州网营广告有限公司_潍坊关键词优化平台_百度搜索官网

宣传片制作费用报价表_广州网营广告有限公司_潍坊关键词优化平台_百度搜索官网

2025/4/18 10:49:22 来源:https://blog.csdn.net/gaosw0521/article/details/142375250  浏览:    关键词:宣传片制作费用报价表_广州网营广告有限公司_潍坊关键词优化平台_百度搜索官网
宣传片制作费用报价表_广州网营广告有限公司_潍坊关键词优化平台_百度搜索官网

1 背景

最近项目上要求开发一个查询接口,刚开发完成后,测试环境进行自测发现查询效率非常慢,通过打log计算得到SQL执行时间3041ms,实在太慢了。下面简单记录下本次慢SQL优化的过程。

2 相关数据

  • 新增客户表(其它无关字段省略)
create table new_customer_info(id bigint(32) not null auto_increment comment '唯一id' ,ent_name varchar(255) default null comment '企业名称',area_name varchar(50) defalut null comment '区域',register_date datetime default null comment '注册时间',phone_number varchar(50) defalut null comment '手机号',del_flag char(1) default '0' comment '删除标志,0:正常,1:删除',sms_flag char(1) defalut '0' comment '获取手机号标志,0:已获取,1:未获取',will_status char(1) default null comment '合作意向,0:无,1:未联系上,2:有合作意向',...primary key (id)
);
  • 区域表(其它无关字段省略)
create table area_data(area_code varchar(50) default null comment '地区代码',area_name varchar(100) default null comment '地区名称',parent_name varchar(100) default null comment '上级地区名称',...key idx_area_code (area_code)
);
  • 字典数据表(其它无关字段省略)
create table sys_dict_data(dict_label varchar(100) default '' comment '字典标签',dict_value varchar(100) default '' comment '字典键值',dict_type varchar(100) default '' comment '字典类型',...key idx_dict_type (dict_type) using btree,key idx_dict_value (dict_value) using btree
)
  • 开发的查询接口功能:
    该接口返回new_customer_info表中所有已经电话回访后的企业信息列表。

3 原始SQL

SELECT nci.net_name entName,nci.area_name areaName,ad.parent_name cityName,add.dict_label industry,date_format(register_date,'%Y-%m-%d') registerDate,nci.phone_number phoneNumber,nci.will_status willStatus
FROM new_customer_info nci 
LEFT JOIN area_data ad ON ad.area_code = nci.area_name 
LEFT JOIN sys_dict_data sdd ON (nci.industry = sdd.dict_value AND ad.dict_type ='train_industry')
WHERE nci.del_flag = '0' AND nci.sms_flag = '0';

对应的xml语句:

<select id='getNewCustomerInfo' resultType='com.javacoder.domain.NewCustomerVo'>select nci.net_name entName,nci.area_name areaName,ad.parent_name cityName,add.dict_label industry,date_format(register_date,'%Y-%m-%d') registerDate,nci.phone_number phoneNumber,nci.will_status willStatusFROM new_customer_info nci LEFT JOIN area_data ad ON ad.area_code = nci.area_name LEFT JOIN sys_dict_data sdd ON (nci.industry = sdd.dict_value AND ad.dict_type ='train_industry')WHERE nci.del_flag = '0' AND nci.sms_flag = '0'<if test="areaName != null and areaName != ''">and nci.area_name like concat('%',concat(#{entName}),'%'))</if><if test="entName != null and entName != ''">and nci.ent_name like concat('%',concat(#{entName}),'%'))</if><if test="willStatus != null and willStatus != ''">and nci.will_status like concat('%',concat(#{willStatus}),'%'))</if>
</select>

4 优化思路

  1. 分析SQL执行计划: 使用EXPLAIN命令查看SQL的执行计划,分析查询过程中涉及的表、索引、连接方式等信息,找出性能瓶颈

  2. 优化索引

    检查相关表的索引情况,确保new_customer_info表的del_flag、sms_flag、area_name、industry字段,area_data表的area_code、dict_type字段,sys_dict_data表的dict_value字段都建立了合适的索引。

    考虑创建组合索引,例如在new_customer_info表上创建(del_flag, sms_flag, area_name, industry)组合索引,以提高查询效率

  3. 优化连接方式

    将LEFT JOIN改为INNER JOIN,如果area_data和sys_dict_data表中没有匹配的数据,则不需要返回new_customer_info表中的数据。

    调整连接顺序,将过滤条件较多的表放在前面连接,以减少中间结果集的大小

  4. 优化查询条件

    将WHERE条件中的常量条件提前,例如将ad.dict_type ='train_industry’放在LEFT JOIN条件中。

    使用EXISTS或IN子查询代替JOIN操作,如果子查询结果集较小

  5. 优化代码逻辑
    通过优化代码执行逻辑,来提高SQL执行效率。

5 优化过程

5.1 分析SQL执行计划

explain SELECT nci.net_name entName,nci.area_name areaName,ad.parent_name cityName,add.dict_label industry,date_format(register_date,'%Y-%m-%d') registerDate,nci.phone_number phoneNumber,nci.will_status willStatus
FROM new_customer_info nci 
LEFT JOIN area_data ad ON ad.area_code = nci.area_name 
LEFT JOIN sys_dict_data sdd ON (nci.industry = sdd.dict_value AND ad.dict_type ='train_industry')
WHERE nci.del_flag = '0' AND nci.sms_flag = '0';

explain 输出结果中各个字段的含义:

  • id 列:查询的标识符。

  • select_type 列:查询的类型。常见的类型有:

    SIMPLE:简单查询,不包含子查询或者 UNION 查询。
    PRIMARY:查询中如果包含子查询,则最外层查询被标记为 PRIMARY。
    SUBQUERY:子查询。
    DERIVED:派生表的 SELECT,FROM 子句的子查询。

  • table 列:查的哪个表。

  • type 列:表示 MySQL 在表中找到所需行的方式,性能从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL。

    system,表只有一行,一般是系统表,往往不需要进行磁盘 IO,速度非常快
    const、eq_ref、ref:这些类型表示 MySQL 可以使用索引来查找单个行,其中 const 是最优的,表示查询最多返回一行。
    range:只检索给定范围的行,使用索引来检索。在where语句中使用 bettween…and、<、>、<=、in 等条件查询 type 都是 range。
    index:遍历索引树读取。
    ALL:全表扫描,效率最低。

  • possible_keys 列:可能会用到的索引,但并不一定实际被使用。

  • key 列:实际使用的索引。如果为 NULL,则没有使用索引。

  • key_len 列:MySQL 决定使用的索引长度(以字节为单位)。当表有多个索引可用时,key_len 字段可以帮助识别哪个索引最有效。通常情况下,更短的 key_len 意味着数据库在比较键值时需要处理更少的数据。

  • ref 列:用于与索引列比较的值来源。

    const:表示常量,这个值是在查询中被固定的。例如在 WHERE column = 'value’中。
    一个或多个列的名称,通常在 JOIN 操作中,表示 JOIN 条件依赖的字段。
    NULL,表示没有使用索引,或者查询使用的是全表扫描。

  • rows 列:估算查到结果集需要扫描的数据行数,原则上 rows 越少越好。

  • Extra 列:附加信息。

    Using index:表示只利用了索引。
    Using where:表示使用了 WHERE 过滤。
    Using temporary :表示使用了临时表来存储中间结果。

5.2 优化索引

  • 在new_customer_info表上创建组合索引
CREATE INDEX idx_nci_del_sms_area_industry ON new_customer_info (del_flag, sms_flag, area_name, industry);
  • 在area_data表上创建组合索引
CREATE INDEX idx_ad_area_code_dict_type ON area_data (area_code, dict_type);
  • 在在sys_dict_data表上创建组合索引
CREATE INDEX idx_sdd_dict_value_dict_type ON sys_dict_data (dict_value,dict_type);
  • 优化结果:SQL执行耗时从3041ms降低到2780ms,效果并不明显,需继续优化。

5.3 优化连接方式

  • 将LEFT JOIN改为INNER JOIN
SELECT nci.net_name entName,nci.area_name areaName,ad.parent_name cityName,add.dict_label industry,date_format(register_date,'%Y-%m-%d') registerDate,nci.phone_number phoneNumber,nci.will_status willStatus
FROM new_customer_info nci 
inner JOIN area_data ad ON ad.area_code = nci.area_name 
inner JOIN sys_dict_data sdd ON (nci.industry = sdd.dict_value AND ad.dict_type ='train_industry')
WHERE nci.del_flag = '0' AND nci.sms_flag = '0';
  • 优化结果:不可行,实际可能会存在new_customer_info表中area_name与area_data表中的area_code对应不上的情况,如果用INNER JOIN,会导致查询出的数据不完整。

5.4 优化代码逻辑

  • 优化前代码逻辑:先查询出全部的new_customer_info表数据,然后用Stream流过滤掉willStatus为null的数据,最后返回。在这个过程中,由于new_costomer_info表的数据量很大,area_data表和sys_dict_data表的数据量较小,通过LEFT JOIN连接三表查询效率很慢。
  • 优化后代码逻辑:先将过滤willStatus为空的逻辑放到SQL语句中,减少连接的数据量。最后无需再通过Stream流过滤数据,直接返回查询结果即可。
  • 优化后的SQL
SELECT nci.net_name entName,nci.area_name areaName,ad.parent_name cityName,add.dict_label industry,date_format(register_date,'%Y-%m-%d') registerDate,nci.phone_number phoneNumber,nci.will_status willStatus
FROM new_customer_info nci 
inner JOIN area_data ad ON ad.area_code = nci.area_name 
inner JOIN sys_dict_data sdd ON (nci.industry = sdd.dict_value AND ad.dict_type ='train_industry')
WHERE nci.del_flag = '0' AND nci.sms_flag = '0' and nci.will_status is not null;
  • 对应的xml语句
<select id='getNewCustomerInfo' resultType='com.javacoder.domain.NewCustomerVo'>select nci.net_name entName,nci.area_name areaName,ad.parent_name cityName,add.dict_label industry,date_format(register_date,'%Y-%m-%d') registerDate,nci.phone_number phoneNumber,nci.will_status willStatusFROM new_customer_info nci LEFT JOIN area_data ad ON ad.area_code = nci.area_name LEFT JOIN sys_dict_data sdd ON (nci.industry = sdd.dict_value AND ad.dict_type ='train_industry')WHERE nci.del_flag = '0' AND nci.sms_flag = '0'<if test="areaName != null and areaName != ''">and nci.area_name like concat('%',concat(#{entName}),'%'))</if><if test="entName != null and entName != ''">and nci.ent_name like concat('%',concat(#{entName}),'%'))</if><if test="willStatus != null and willStatus != ''">and nci.will_status like concat('%',concat(#{willStatus}),'%'))</if>and nci.will_status is not null
</select>
  • 优化结果:SQL执行耗时从2780ms降低到300ms,效果明显,但还有优化空间。

5.5 最后的优化

  • 再次使用explain分析SQL执行计划,发现SQL执行过程中new_customer_info表输出结果的type列返回的是ALL,表示全表扫描。
  • 优化方案:在new_customer_info表上创建索引
create index idx_will_status on new_customer_info (will_status);
  • 优化结果:SQL执行耗时从300ms降低到10ms以内,效果显著,达到了预期目标。

6 总结

SQL优化是一个需要不断尝试和调整的过程,需要结合具体的业务场景和数据库特性进行分析和优化。通过业务逻辑代码优化、合理的索引设计、连接方式优化、查询条件优化等手段,可以有效提升SQL语句的执行效率,提高系统性能。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com