使用MySql视图时出现问题-速度非常慢,但原因是什么?

使用MySql视图时出现问题-速度非常慢,但原因是什么?,mysql,performance,select,subquery,sql-view,Mysql,Performance,Select,Subquery,Sql View,我在使用mysql视图时遇到了一个大问题。 我正在生成一个视图,在该视图中,我连接了几个表以接收我真正需要的信息 我有以下看法: CREATE OR REPLACE VIEW view_test AS SELECT nve_nr.nve_nvenr AS collonr, CONCAT (adr_emp.adr_name1, "\n", adr_emp.adr_name2, "\n", adr_emp.adr_strasse, "\n", adr_emp.adr_land , " -

我在使用mysql视图时遇到了一个大问题。 我正在生成一个视图,在该视图中,我连接了几个表以接收我真正需要的信息

我有以下看法:

CREATE OR REPLACE VIEW view_test AS

SELECT nve_nr.nve_nvenr AS collonr,
CONCAT (adr_emp.adr_name1, "\n", adr_emp.adr_name2, "\n", adr_emp.adr_strasse, "\n", adr_emp.adr_land , " -     ", adr_emp.adr_plz, " ", adr_emp.adr_ort) AS emp_adr,

UNIX_TIMESTAMP((SELECT MAX(t_1.colst_timestamp) FROM tbl_collo_status t_1 WHERE t_1.colst_nve_id = 
nve_nr.nve_id AND t_1.colst_status_code IN (10, 11, 76))) AS status_x,

UNIX_TIMESTAMP((SELECT MAX(t_2.colst_timestamp) FROM tbl_collo_status t_2 WHERE t_2.colst_nve_id = 
nve_nr.nve_id AND t_2.colst_status_code IN (20,25,91))) AS status_y,

UNIX_TIMESTAMP((SELECT MAX(t_3.colst_timestamp) FROM tbl_collo_status t_3 WHERE t_3.colst_nve_id = 
nve_nr.nve_id AND t_3.colst_status_code IN (30,99,104))) AS status_z,

TIME_TO_SEC(TIMEDIFF((SELECT MAX(t_2.colst_timestamp) FROM tbl_collo_status t_2 WHERE t_2.colst_nve_id = 
nve_nr.nve_id AND t_2.colst_status_code IN (20,25,91)), (SELECT MAX(t_1.colst_timestamp) FROM tbl_collo_status t_1 
WHERE t_1.colst_nve_id = nve_nr.nve_id AND t_1.colst_status_code IN (10, 11, 76)))) AS timediff_xy,

TIME_TO_SEC(TIMEDIFF((SELECT MAX(t_3.colst_timestamp) FROM tbl_collo_status t_3 WHERE t_3.colst_nve_id = 
nve_nr.nve_id AND t_3.colst_status_code IN (30,99,104)), (SELECT MAX(t_2.colst_timestamp) FROM tbl_collo_status t_2 
WHERE t_2.colst_nve_id = nve_nr.nve_id AND t_2.colst_status_code IN (20,25,91)))) AS timediff_yz,

TIME_TO_SEC(TIMEDIFF((SELECT MAX(t_3.colst_timestamp) FROM tbl_collo_status t_3 WHERE t_3.colst_nve_id = 
nve_nr.nve_id AND t_3.colst_status_code IN (30,99,104)), (SELECT MAX(t_1.colst_timestamp) FROM tbl_collo_status t_1 
WHERE t_1.colst_nve_id = nve_nr.nve_id AND t_1.colst_status_code IN (10, 11, 76)))) AS timediff_xz,

CAST(SUBSTR(nve_nr.nve_nvenr, 1, 3) AS UNSIGNED INTEGER) AS filter_collonr,

(SELECT t_5.colst_status_code FROM tbl_collo_status t_5 WHERE t_5.colst_nve_id=nve_nr.nve_id ORDER BY 
t_5.colst_timestamp DESC LIMIT 1) AS filter_last_status,

sdg.sdg_kunde AS filter_kunden_id,

sdg.sdg_id AS filter_sdg_id,

nve_nr.nve_id AS filter_nve_id,

adr_emp.adr_id AS filter_adr_emp_id

FROM ((tbl_nve_nr nve_nr LEFT JOIN tbl_sendungen sdg ON nve_nr.nve_sdg_id = sdg.sdg_id)

LEFT JOIN tbl_adressen adr_emp ON adr_emp.adr_id = sdg.sdg_adr2_id);
现在,我在该视图中有超过250000个数据集,如果我在该视图上启动一个select,我将需要超过20分钟的时间来接收结果。 Explain Select将返回以下内容:

//!![解释从视图中选择][1]

我不能在没有10个声誉的情况下发布图片,所以我会这样尝试:

SELECT SQL_CALC_FOUND_ROWS 
sdg.sdg_lieferschein AS referenz, 
nve_nr.nve_nvenr AS collonr, 
nve_nr.nve_last_timestamp AS filter_status_time, 
nve_nr.nve_last_status AS filter_last_status, 
sdg.sdg_kunde AS filter_kunden_id, 
sdg.sdg_id AS filter_sdg_id, 
nve_nr.nve_id AS filter_nve_id, 
adr_emp.adr_id AS filter_adr_emp_id, 
adr_emp.adr_name1 AS emp_adr_name1, 
adr_emp.adr_name2 AS emp_adr_name2, 
adr_emp.adr_land AS emp_adr_land, 
adr_emp.adr_plz AS emp_adr_plz, 
adr_emp.adr_ort AS emp_adr_ort,
UNIX_TIMESTAMP(t_1.colst_timestamp) AS status_x, 
t_1.colst_status_code AS status_code_x, 
UNIX_TIMESTAMP(t_2.colst_timestamp) AS status_y, 
t_2.colst_status_code AS status_code_y, 
UNIX_TIMESTAMP(t_3.colst_timestamp) AS status_z, 
t_3.colst_status_code AS status_code_z, 
TIME_TO_SEC(TIMEDIFF(t_2.colst_timestamp, t_1.colst_timestamp)) AS timediff_xy, 
TIME_TO_SEC(TIMEDIFF(t_3.colst_timestamp, t_2.colst_timestamp)) AS timediff_yz, 
TIME_TO_SEC(TIMEDIFF(t_3.colst_timestamp, t_1.colst_timestamp)) AS timediff_xz, 
CAST(SUBSTR(nve_nr.nve_nvenr, 1, 3) AS UNSIGNED INTEGER) AS filter_collonr 
FROM tbl_nve_nr nve_nr 
LEFT JOIN tbl_sendungen sdg 
ON nve_nr.nve_sdg_id = sdg.sdg_id 
LEFT JOIN tbl_adressen adr_emp 
ON (adr_emp.adr_id = sdg.sdg_adr2_id) 
LEFT JOIN tbl_collo_status t_1 
ON (t_1.colst_nve_id = nve_nr.nve_id AND t_1.colst_aktiv = 1 AND t_1.colst_status_code IN (10, 11, 76)) 
LEFT JOIN tbl_collo_status t_2 
ON (t_2.colst_nve_id = nve_nr.nve_id AND t_2.colst_aktiv = 1 AND t_2.colst_status_code IN (20,25,91)) 
LEFT JOIN tbl_collo_status t_3 
ON (t_3.colst_nve_id = nve_nr.nve_id AND t_3.colst_aktiv = 1 AND t_3.colst_status_code IN (30,99,104)) 
GROUP BY collonr 
ORDER BY collonr DESC 
LIMIT 900, 75
有谁能告诉我,我能做些什么来加速观看? 在不使用视图的情况下执行查询将需要大约2分钟的时间,最多需要从250.000个可用数据集中选择25个数据集

//编辑: 所以我用另一种方法解决了这个问题: 下面描述的解决方案不能保证SQL查询的工作速度足够快,因此我采用以下方法解决:

删除视图,因为不再需要它们, 更改表nve_nr,添加两个字段作为最后状态和该状态的时间戳。 如果时间戳比现有时间戳新,则在collo_状态上创建一个触发器以替换该值。 ->因此,一个子查询的速度从2分钟提高到近60秒

重建索引并直接在php中运行查询 ->php中的代码更多,但更为繁杂-现在速度高达13秒:

使用新字段更新数据库包括查找当前最新状态的过程

因此,新查询如下所示:

SELECT SQL_CALC_FOUND_ROWS 
sdg.sdg_lieferschein AS referenz, 
nve_nr.nve_nvenr AS collonr, 
nve_nr.nve_last_timestamp AS filter_status_time, 
nve_nr.nve_last_status AS filter_last_status, 
sdg.sdg_kunde AS filter_kunden_id, 
sdg.sdg_id AS filter_sdg_id, 
nve_nr.nve_id AS filter_nve_id, 
adr_emp.adr_id AS filter_adr_emp_id, 
adr_emp.adr_name1 AS emp_adr_name1, 
adr_emp.adr_name2 AS emp_adr_name2, 
adr_emp.adr_land AS emp_adr_land, 
adr_emp.adr_plz AS emp_adr_plz, 
adr_emp.adr_ort AS emp_adr_ort,
UNIX_TIMESTAMP(t_1.colst_timestamp) AS status_x, 
t_1.colst_status_code AS status_code_x, 
UNIX_TIMESTAMP(t_2.colst_timestamp) AS status_y, 
t_2.colst_status_code AS status_code_y, 
UNIX_TIMESTAMP(t_3.colst_timestamp) AS status_z, 
t_3.colst_status_code AS status_code_z, 
TIME_TO_SEC(TIMEDIFF(t_2.colst_timestamp, t_1.colst_timestamp)) AS timediff_xy, 
TIME_TO_SEC(TIMEDIFF(t_3.colst_timestamp, t_2.colst_timestamp)) AS timediff_yz, 
TIME_TO_SEC(TIMEDIFF(t_3.colst_timestamp, t_1.colst_timestamp)) AS timediff_xz, 
CAST(SUBSTR(nve_nr.nve_nvenr, 1, 3) AS UNSIGNED INTEGER) AS filter_collonr 
FROM tbl_nve_nr nve_nr 
LEFT JOIN tbl_sendungen sdg 
ON nve_nr.nve_sdg_id = sdg.sdg_id 
LEFT JOIN tbl_adressen adr_emp 
ON (adr_emp.adr_id = sdg.sdg_adr2_id) 
LEFT JOIN tbl_collo_status t_1 
ON (t_1.colst_nve_id = nve_nr.nve_id AND t_1.colst_aktiv = 1 AND t_1.colst_status_code IN (10, 11, 76)) 
LEFT JOIN tbl_collo_status t_2 
ON (t_2.colst_nve_id = nve_nr.nve_id AND t_2.colst_aktiv = 1 AND t_2.colst_status_code IN (20,25,91)) 
LEFT JOIN tbl_collo_status t_3 
ON (t_3.colst_nve_id = nve_nr.nve_id AND t_3.colst_aktiv = 1 AND t_3.colst_status_code IN (30,99,104)) 
GROUP BY collonr 
ORDER BY collonr DESC 
LIMIT 900, 75

//[1] :

主要问题可能是索引,但也很值得删除相关子查询。大概是这样的:-

CREATE OR REPLACE VIEW view_test AS

SELECT nve_nr.nve_nvenr AS collonr,
CONCAT (adr_emp.adr_name1, "\n", adr_emp.adr_name2, "\n", adr_emp.adr_strasse, "\n", adr_emp.adr_land , " -     ", adr_emp.adr_plz, " ", adr_emp.adr_ort) AS emp_adr,

UNIX_TIMESTAMP((SELECT MAX(t_1.colst_timestamp) FROM tbl_collo_status t_1 WHERE t_1.colst_nve_id = 
nve_nr.nve_id AND t_1.colst_status_code IN (10, 11, 76))) AS status_x,

UNIX_TIMESTAMP((SELECT MAX(t_2.colst_timestamp) FROM tbl_collo_status t_2 WHERE t_2.colst_nve_id = 
nve_nr.nve_id AND t_2.colst_status_code IN (20,25,91))) AS status_y,

UNIX_TIMESTAMP((SELECT MAX(t_3.colst_timestamp) FROM tbl_collo_status t_3 WHERE t_3.colst_nve_id = 
nve_nr.nve_id AND t_3.colst_status_code IN (30,99,104))) AS status_z,

TIME_TO_SEC(TIMEDIFF((SELECT MAX(t_2.colst_timestamp) FROM tbl_collo_status t_2 WHERE t_2.colst_nve_id = 
nve_nr.nve_id AND t_2.colst_status_code IN (20,25,91)), (SELECT MAX(t_1.colst_timestamp) FROM tbl_collo_status t_1 
WHERE t_1.colst_nve_id = nve_nr.nve_id AND t_1.colst_status_code IN (10, 11, 76)))) AS timediff_xy,

TIME_TO_SEC(TIMEDIFF((SELECT MAX(t_3.colst_timestamp) FROM tbl_collo_status t_3 WHERE t_3.colst_nve_id = 
nve_nr.nve_id AND t_3.colst_status_code IN (30,99,104)), (SELECT MAX(t_2.colst_timestamp) FROM tbl_collo_status t_2 
WHERE t_2.colst_nve_id = nve_nr.nve_id AND t_2.colst_status_code IN (20,25,91)))) AS timediff_yz,

TIME_TO_SEC(TIMEDIFF((SELECT MAX(t_3.colst_timestamp) FROM tbl_collo_status t_3 WHERE t_3.colst_nve_id = 
nve_nr.nve_id AND t_3.colst_status_code IN (30,99,104)), (SELECT MAX(t_1.colst_timestamp) FROM tbl_collo_status t_1 
WHERE t_1.colst_nve_id = nve_nr.nve_id AND t_1.colst_status_code IN (10, 11, 76)))) AS timediff_xz,

CAST(SUBSTR(nve_nr.nve_nvenr, 1, 3) AS UNSIGNED INTEGER) AS filter_collonr,

MAX(t_5.colst_status_code) AS filter_last_status,

sdg.sdg_kunde AS filter_kunden_id,

sdg.sdg_id AS filter_sdg_id,

nve_nr.nve_id AS filter_nve_id,

adr_emp.adr_id AS filter_adr_emp_id

FROM tbl_nve_nr nve_nr 

LEFT JOIN tbl_sendungen sdg ON nve_nr.nve_sdg_id = sdg.sdg_id

LEFT JOIN tbl_adressen adr_emp ON adr_emp.adr_id = sdg.sdg_adr2_id

INNER JOIN tbl_collo_status t_5  ON t_5.colst_nve_id = nve_nr.nve_id

GROUP BY collonr, emp_adr, status_x, status_y, status_z, timediff_xy, timediff_yz, timediff_xz, filter_collonr, filter_kunden_id, filter_sdg_id, filter_nve_id, filter_adr_emp_id
问题是,您的查询有很多相互关联的子查询,这些子查询通常执行得很糟糕

最好的解决方案可能是将所有相关子查询替换为针对其他视图的连接,而这些视图包含选择项

编辑-拆分其他子选择:-

创建视图:-

CREATE ALGORITHM = UNDEFINED VIEW vw_MaxTimeStamp_10_11_76 AS SELECT t_1.colst_nve_id, MAX(t_1.colst_timestamp) AS MaxTimestamp FROM tbl_collo_status t_1 WHERE t_1.colst_status_code IN (10, 11, 76) GROUP BY t_1.colst_nve_id

CREATE ALGORITHM = UNDEFINED VIEW vw_MaxTimeStamp_20_25_91 AS SELECT t_1.colst_nve_id, MAX(t_1.colst_timestamp) AS MaxTimestamp FROM tbl_collo_status t_1 WHERE t_1.colst_status_code IN (20,25,91) GROUP BY t_1.colst_nve_id

CREATE ALGORITHM = UNDEFINED VIEW vw_MaxTimeStamp_30_99_104 AS SELECT t_1.colst_nve_id, MAX(t_1.colst_timestamp) AS MaxTimestamp FROM tbl_collo_status t_1 WHERE t_1.colst_status_code IN (30,99,104) GROUP BY t_1.colst_nve_id

CREATE ALGORITHM = UNDEFINED VIEW vw_MaxStatusCode AS SELECT colst_nve_id, MAX(t_5.colst_status_code) AS MaxStatusCode FROM tbl_collo_status t_5 GROUP BY colst_nve_id
然后,您的主视图可以简化为类似这样的内容,但没有经过测试,因此可能会出现一些拼写错误

CREATE OR REPLACE VIEW view_test AS

SELECT nve_nr.nve_nvenr AS collonr,
CONCAT (adr_emp.adr_name1, "\n", adr_emp.adr_name2, "\n", adr_emp.adr_strasse, "\n", adr_emp.adr_land , " -     ", adr_emp.adr_plz, " ", adr_emp.adr_ort) AS emp_adr,
UNIX_TIMESTAMP(vw_MaxTimeStamp_10_11_76.MaxTimestamp) AS status_x,
UNIX_TIMESTAMP(vw_MaxTimeStamp_20_25_91.MaxTimestamp) AS status_y,
UNIX_TIMESTAMP(vw_MaxTimeStamp_30_99_104.MaxTimestamp) AS status_z,
TIME_TO_SEC(TIMEDIFF(vw_MaxTimeStamp_20_25_91.MaxTimestamp, vw_MaxTimeStamp_10_11_76.MaxTimestamp)) AS timediff_xy,
TIME_TO_SEC(TIMEDIFF(vw_MaxTimeStamp_30_99_104.MaxTimestamp, vw_MaxTimeStamp_20_25_91.MaxTimestamp)) AS timediff_yz,
TIME_TO_SEC(TIMEDIFF(vw_MaxTimeStamp_30_99_104.MaxTimestamp, vw_MaxTimeStamp_10_11_76.MaxTimestamp)) AS timediff_xz,
CAST(SUBSTR(nve_nr.nve_nvenr, 1, 3) AS UNSIGNED INTEGER) AS filter_collonr,
vw_MaxStatusCode.MaxStatusCode AS filter_last_status
sdg.sdg_kunde AS filter_kunden_id,
sdg.sdg_id AS filter_sdg_id,
nve_nr.nve_id AS filter_nve_id,
adr_emp.adr_id AS filter_adr_emp_id
FROM tbl_nve_nr nve_nr 
LEFT JOIN tbl_sendungen sdg ON nve_nr.nve_sdg_id = sdg.sdg_id
LEFT JOIN tbl_adressen adr_emp ON adr_emp.adr_id = sdg.sdg_adr2_id
INNER JOIN tbl_collo_status t_5  ON t_5.colst_nve_id = nve_nr.nve_id
LEFT OUTER JOIN vw_MaxTimeStamp_10_11_76 ON vw_MaxTimeStamp_10_11_76.colst_nve_id = nve_nr.nve_id
LEFT OUTER JOIN vw_MaxTimeStamp_20_25_91 ON vw_MaxTimeStamp_20_25_91.colst_nve_id = nve_nr.nve_id
LEFT OUTER JOIN vw_MaxTimeStamp_30_99_104 ON vw_MaxTimeStamp_30_99_104.colst_nve_id = nve_nr.nve_id
LEFT OUTRER JOIN vw_MaxStatusCode ON vw_MaxStatusCode.colst_nve_id = nve_nr.nve_id

感谢您的快速回复,但是在将子查询移动到联接时,我将得到一个错误1349-视图的SELECT在FROM子句中包含一个子查询,忘记了对视图的限制。我会快速编辑。好的,谢谢。这个查询现在的运行速度已经快得多了。现在我尝试将子查询分离到不同的视图,然后我将创建一个从其他视图中选择的视图?!?我要试试看:谢谢你的帮助。我添加了一些代码,希望能将其他子选择拆分为视图。