我是一名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)
谢谢您的帮助。
答案 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计划。