使用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);
现在我在该视图中拥有超过250.000个数据集,如果我在该视图上启动选择,我将花费超过20分钟来接收结果。 Explain Select将返回以下内容:
//![解释从视图中选择] [1]
我不能在没有10个声誉的情况下发布图片,所以我会这样试试:
有谁能告诉我我能做些什么来加快视野? 在不使用视图的情况下执行查询将需要大约2分钟,限制为25个数据集,可以从250.000个可用数据集中选择。
//编辑: 所以我用另一种方式解决了这个问题:) 下面描述的解决方案并没有使SQL-Query的工作速度更快,所以我通过以下方式解决了这个问题:
删除视图,因为不再需要它们了, 更改表nve_nr为最后状态和时间戳添加两个字段。 如果timestamp比现有值更新,则在collo_status上创建一个替换该值的触发器。 - >所以一个子查询更少 - 从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
答案 0 :(得分: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
问题是你的查询有很多与co相关的子查询,而这些查询通常表现不佳。
可能最好的解决方案是将所有与co相关的子查询替换为与其他视图的连接(使用包含选择的视图)
编辑 - 拆分其他子选择: -
创建视图: -
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