mysql如何优化以下语句,查询耗时太久了?

mysql如何优化以下语句,查询耗时太久了?,第1张

一般进行性能分析,分如下三步:首先需要使用慢查询日志功能,去获取所有查询时间比较长的SQL语句其次查看执行计划查看有问题的SQL的执行计划 explain最后可以使用show profile查看有问题的SQL的性能使用情况慢查询日志分析首先我们要使用慢查询日志,因为它收集了查询时间比较长的SQL语句,但使用之前必须开启慢查询日志,在配置文件my.cnf(一般为/etc/my.cnf)中的[mysqld] 增加如下参数:slow_query_log=ONlong_query_time=3slow_query_log_file=/var/lib/mysql/slow-log.log复制代码增加这些参数之后,重启MySQL,可以进行查询慢查询日志是否开启。1. 任何地方都不要使用 select * from t,用具体的字段列表代替“*“,不要返回用不到的任何字段。2. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。3. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。4. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。5. 尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间, 其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。6. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。7. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where和order by相关的列上建立索引。8. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。例如: select * from t where num is null我们可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:select * from t where num=0。

当然可以,就是在mysql存储过程中使用动态sql,就可以拼接sql,然后执行了。

给你复制一段,如果不满意,自己搜索 mysql 存储过程  动态sql 就可以了

DROP PROCEDURE IF EXISTS SearchByDoctor

CREATE PROCEDURE  SearchByDoctor(

   IN DoctorId VARCHAR(50),

   IN deptId VARCHAR(50),

   IN beginDate VARCHAR(20),

   IN endDate VARCHAR(20),

   IN StandDeptId VARCHAR(50),

   IN OperationFlag VARCHAR(50),

   IN SsczflId  VARCHAR(50),

   OUT OperNum INT,

   OUT AvgDangerIndex DOUBLE,

   OUT OperGrCase INT

BEGIN

DECLARE cal1 VARCHAR(800)

  DECLARE cal2 VARCHAR(800)

SET cal1="SELECT COUNT(1),AVG(DANGER_INDEX) INTO @para1,@para2  FROM yw_ssxxb WHERE 1=1 "

  SET cal2="SELECT COUNT(1) INTO @para3 FROM gr_grbw WHERE OPE_RELID IN (SELECT RELID FROM yw_ssxxb WHERE 1=1"

 #拼接医生id

   SET cal1=CONCAT(cal1," ","AND OPEDOC_ID = ","'",DoctorId,"'")

   SET cal2=CONCAT(cal2," ","AND OPEDOC_ID = ","'",DoctorId,"'")

  #拼接科室id

IF deptId <>'' THEN 

SET cal1=CONCAT(cal1,"AND DEPT_ID =","'",deptId,"'")  

  END IF

 #拼接开始结束日期

  IF beginDate<>'' AND endDate <>'' THEN 

  SET cal1=CONCAT(cal1," ","AND OPER_AT BETWEEN ","'",beginDate,"'"," AND ","'",endDate,"'")

  END IF

  #拼接标准科室

  IF StandDeptId<>'' THEN

  SET cal1=CONCAT(cal1," ","AND DEPT_ID IN ( SELECT ID FROM department WHERE STAND_DEPT_ID = ","'",StandDeptId,"'",")")   

  END IF

 #拼接数据来源

  IF OperationFlag <>'' THEN  

  SET cal1=CONCAT(cal1," ","AND OPEPARTKINDID IN (SELECT ID FROM zh_ssczfl WHERE FLAG= ","'",OperationFlag,"'",")")

  END IF

 #拼接手术 *** 作类别

 IF SsczflId <> '' THEN

 SET cal1=CONCAT(cal1," ","AND OPEPARTKINDID = ","'",SsczflId,"'")  

 END IF

 SET cal2 =CONCAT(cal2,")")  

SET @sql1=cal1

  SET @sql2=cal2

PREPARE stmt1 FROM @sql1

EXECUTE stmt1

DEALLOCATE PREPARE stmt1 

 PREPARE stmt2 FROM @sql2

EXECUTE stmt2

DEALLOCATE PREPARE stmt2 

 SET OperNum=@para1

  SET AvgDangerIndex=@para2

  SET OperGrCase=@para3  

END

# mysql不支持其它复杂数据库的类似 rank() over 的排名和统计查询# 只能通过变通的子查询和逻辑计算方式来实现,对于中小数据量可以考虑-- rank 排名实现select inline_rownum, aa, cc, amt, orderid FROM(select# logic_cal 只是实现计数器计算的,每次逐条查询时会对比当前 cc 与 @last_cc 是否相同,如果不同则把当前该列值赋于 @last_cc 并重设计数器 @num := 1,否则计数器自加 @num := @num + 1(case when cc <>@last_cc then concat(@last_cc := cc, @num := 1 ) else concat(@last_cc, @num := @num + 1) end ) logic_cal, @num as inline_rownum, aa, cc, amt, orderidfrom tb_rank,( select @last_cc := '') t, # 初始化 @last_cc 为 '', 如要检查的列(基于计数器统计的列)是int型,则初始化为0varchar型初始化为''( select @num := 0 ) t2 # 初始化@num为0order by cc, orderid asc # 排序的方式会影响@num的生成,因为logic_cal是逐行计算的) twhere inline_rownum <= floor(amt*0.8) #限制条数,取常量值或其他order by cc,orderid asc


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/8409244.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-16
下一篇2023-04-16

发表评论

登录后才能评论

评论列表(0条)

    保存