极慢查询的MySQL查询优化

时间:2019-07-04 12:51:23

标签: mysql optimization query-optimization execution-time

我是一名Web开发人员,也是我第一次在SO上发帖。

今天,我正在寻求您的帮助,因为我已经尝试过所有可能的方法。

我创建了一个SAAS Web应用程序,供销售人员在地面上使用,它包含一个脱机版本,用户无需连接即可使用它。

随着数据库的变大,查询将花费越来越多的时间来执行。

今天,我面临一个大问题,即当用户试图显示查询结果时,查询导致超时。

所以,这是转储:

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";

-- 86 rows
CREATE TABLE t2 (
  id_t2 int(11) NOT NULL,
  quantite_t2 int(11) NOT NULL,
  ca_t2 decimal(10,2) NOT NULL,
  date_t2 date NOT NULL,
  import_t2 datetime NOT NULL,
  id_enseigne int(11) NOT NULL,
  id_t3 int(11) NOT NULL,
  annee_t2 int(11) NOT NULL,
  mois_t2 int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- 2012065 rows
CREATE TABLE t1 (
  id_t2 int(11) NOT NULL,
  id_t0 bigint(20) NOT NULL,
  id_t4 bigint(20) NOT NULL,
  quantite_t1 int(11) NOT NULL,
  ca_t1 decimal(10,2) NOT NULL,
  pvc_moyen_t1 float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- 388 rows
CREATE TABLE t4 (
  id_t4 int(11) NOT NULL,
  lib_t4 text NOT NULL,
  libcourt_t4 varchar(255) NOT NULL,
  ean_t4 varchar(255) NOT NULL,
  pcb_t4 int(11) NOT NULL,
  pcb2_t4 int(11) NOT NULL,
  fam_t4 varchar(255) NOT NULL,
  gam_t4 varchar(255) NOT NULL DEFAULT '0',
  stat_t4 int(11) NOT NULL DEFAULT 1,
  vmh_t4 decimal(10,2) NOT NULL,
  detail_t4 text NOT NULL,
  ingr_t4 text NOT NULL,
  weight_t4 float NOT NULL,
  lifetime_t4 varchar(255) NOT NULL,
  pmc1_t4 float NOT NULL,
  pmc2_t4 float NOT NULL,
  dim_t4 decimal(10,2) NOT NULL,
  ordre_t4 int(11) NOT NULL,
  created_t4 datetime NOT NULL,
  updated_t4 datetime NOT NULL,
  updated_img_t4 datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- 1 row
CREATE TABLE t3 (
  id_t3 int(11) NOT NULL,
  nom_t3 text NOT NULL,
  stat_t3 int(11) NOT NULL,
  created_t3 datetime NOT NULL,
  deleted_t3 datetime NOT NULL,
  updated_t3 datetime NOT NULL,
  ip_create_t3 text NOT NULL,
  ip_delete_t3 text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;


ALTER TABLE t2
  ADD PRIMARY KEY (id_t2),
  ADD KEY annee_t2 (annee_t2,mois_t2,date_t2);

ALTER TABLE t1
  ADD PRIMARY KEY (id_t2,id_t0,id_t4);

ALTER TABLE t4
  ADD PRIMARY KEY (id_t4,ean_t4),
  ADD KEY ean_t4 (ean_t4),
  ADD KEY id_t4 (id_t4);

ALTER TABLE t3
  ADD PRIMARY KEY (id_t3);


ALTER TABLE t2
  MODIFY id_t2 int(11) NOT NULL AUTO_INCREMENT;

ALTER TABLE t4
  MODIFY id_t4 int(11) NOT NULL AUTO_INCREMENT;

ALTER TABLE t3
  MODIFY id_t3 int(11) NOT NULL AUTO_INCREMENT;

COMMIT;

下面执行的查询大约需要4分钟才能执行:

-- execution time 228 seconds
SELECT SUM(t1.ca_t1) AS ca_t4, SUM(t1.quantite_t1) AS qte_t4,
       t4.fam_t4, t4.gam_t4, t4.lib_t4, t4.ean_t4, t4.id_t4,
       t2.annee_t2, t2.mois_t2, COUNT(t1.id_t0) AS count_mag,
       t3.id_t3, t3.nom_t3
FROM t1 t1
INNER JOIN t2 t2 ON t2.id_t2 = t1.id_t2
LEFT JOIN t3 t3 ON t2.id_t3 = t3.id_t3
INNER JOIN t4 t4 ON t1.id_t4 = t4.ean_t4
WHERE t2.date_t2 BETWEEN "2017-05-01" AND "2019-05-01"
GROUP BY t2.annee_t2, t2.mois_t2, t4.id_t4
ORDER BY ca_t4 DESC;

我尝试了所有已知的优化来帮助我减少执行时间,但没有成功...

说明显示以下内容:

id  select_type    table    type      possible_keys    key        key_len    ref            rows    Extra
1   SIMPLE         t2       ALL       PRIMARY          NULL       NULL       NULL           86      Using where; Using temporary; Using filesort
1   SIMPLE         t3       eq_ref    PRIMARY          PRIMARY    4          db.t2.id_t3    1       
1   SIMPLE         t1       ref       PRIMARY,id_t2    PRIMARY    4          db.t2.id_t2    11266   
1   SIMPLE         t4       ALL       ean_t4           NULL       NULL       NULL           388     Using where; Using join buffer (flat, BNL join)

谢谢您的帮助。

2 个答案:

答案 0 :(得分:1)

  • GROUP BY可能不正确,因为它不包含未夸大的t3列。
  • 您真的要2年加1天吗?也许我们这样:

        t2.date_t2  >=  "2017-05-01"
    AND t2.date_t2   <  "2017-05-01" + INTERVAL 2 YEAR
    
  • JOINing-ON t1.id_t4 = t4.ean_t4时不要混合数据类型:

    ean_t4 varchar(255) NOT NULL,
    id_t4 bigint(20) NOT NULL,
    

(可能还有其他问题,但这应该有所帮助。)

答案 1 :(得分:0)

这看起来像一个相当复杂的查询,有很多地方会使查询变慢。但是,我注意到的第一件事是必须使用双重查询才能使用annee_2索引,这可能就是为什么不使用它的原因。

尝试将id_t3添加到表t2的该索引的末尾:

(annee_t2,mois_t2,date_t2,id_t3)

这应该允许优化程序使用该索引。

再次运行查询(两次,以填充缓冲区高速缓存,仅报告第二个结果),如果不能充分改善,则发布新的EXPLAIN计划。