【发布时间】:2017-07-17 12:33:06
【问题描述】:
我是 MySQL 性能调优的新手,我需要您的帮助来解决我们稍后在设计中将替换表的视图。
要替换的表名为users,具有以下属性: users2 视图具有以下属性:
当我对两个对象执行普通 SELECT 时,它们会同时响应:
SELECT *
FROM `users`
SELECT *
FROM `users2`
但是这些查询的有序版本会导致不同的性能:表有点慢(不到两秒),这次视图大约需要十倍:
SELECT *
FROM `users`
ORDER BY `lastName`, `firstName`
SELECT *
FROM `users2`
ORDER BY `lastName`, `firstName`
显然,属性 Countries_ID 上的表 'a' (addresses) 上的 ALL 正在制造麻烦,所以我做了以下:
ALTER TABLE addresses ADD INDEX (Countries_ID);
这个索引根本没有改变任何东西。所以,我问你的意见,什么可以做得更好。
注意 1:有没有办法在临时列 Countries_ID_2 上创建索引? 注意 2:users2 视图是使用以下 SQL 查询创建的:
CREATE OR REPLACE VIEW users2 AS
(SELECT p.username
, p.password
, p.firstName
, p.lastName
, p.eMail AS email
, a.settlement AS city
, s.name AS country
, pl.languages
, p.description
, p.ID AS ID
, p.phone1
, p.phone2
, CONCAT_WS(' ', a.street, a.addition) AS address
, p.status
, p.publicMail
, ad.name AS Betreuer
FROM addresses a
INNER JOIN addresses_have_persons ap ON a.ID = ap.Addresses_ID
INNER JOIN countries c ON a.Countries_ID = c.ID
INNER JOIN persons p ON a.ID = p.addressID
AND ap.Persons_ID = p.ID
INNER JOIN states s ON a.States_ID = s.ID
INNER JOIN persons_language pl ON p.ID = pl.ID
LEFT JOIN advisors ad ON p.advisorID = ad.ID
-- LEFT JOIN titles t ON t.ID = ad.titleID
);
注意3:虽然persons表中有很多字段是NULL,但是没有一行这些字段都是NULL。
编辑:
CREATE OR REPLACE VIEW persons_language AS
(SELECT lp.Persons_ID AS ID
, GROUP_CONCAT(DISTINCT l.name ORDER BY l.name SEPARATOR ', ') AS languages
FROM languages l
, languages_have_persons lp
WHERE l.ID = lp.Languages_ID
GROUP BY lp.Persons_ID);
没有ORDER BY,语言名称不是按字母顺序排列的,这是我目前想要的。也许,我们可以决定以任何顺序获得它们,但我们会看到。
目前,我做了以下修改,没有任何性能提升:
ALTER TABLE addresses ADD INDEX (Countries_ID);
ALTER TABLE addresses ADD INDEX (States_ID);
ALTER TABLE addresses_have_persons ADD INDEX (Addresses_ID);
ALTER TABLE languages ADD INDEX (name);
ALTER TABLE persons ADD INDEX (addressID);
ALTER TABLE persons ADD INDEX (address2ID);
ALTER TABLE persons ADD INDEX (address3ID);
ALTER TABLE persons ADD INDEX (advisorID);
编辑 2:
我也在另一个网站上讨论过这个问题。那里的讨论让我进行了以下更改以更接近第三范式:
CREATE OR REPLACE TABLE accounts
(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY
, username VARCHAR(50) NOT NULL UNIQUE
, password VARCHAR(255) NOT NULL
, eMail VARCHAR(100) NOT NULL
, Persons_ID INT NOT NULL
);
INSERT INTO accounts (username, password, eMail, Persons_ID)
SELECT username, password, eMail, ID
FROM persons;
persons 表确实只包含最必要的东西,现在具有以下结构:
新表 persons_information 包含所有附加信息:
我使用以下命令重新创建了 users2:
CREATE OR REPLACE VIEW users2 AS
(SELECT ac.username
, ac.password
, p.firstName
, p.lastName
, ac.eMail AS email
, adr.settlement AS city
, s.name AS country
, pl.languages
, pi.description
, ac.Persons_ID AS ID
, pi.phone1
, pi.phone2
, CONCAT_WS(' ', adr.street, adr.addition) AS address
, p.status
, pi.publicMail
, adv.name AS Betreuer
FROM accounts ac
INNER JOIN persons p ON ac.Persons_ID = p.ID
INNER JOIN persons_information pi ON p.ID = pi.ID
INNER JOIN addresses adr ON adr.ID = pi.addressID
INNER JOIN addresses_have_persons ap ON adr.ID = ap.Addresses_ID
AND ap.Persons_ID = p.ID
INNER JOIN countries c ON adr.Countries_ID = c.ID
INNER JOIN states s ON adr.States_ID = s.ID
INNER JOIN persons_language pl ON p.ID = pl.ID
LEFT JOIN advisors adv ON pi.advisorID = adv.ID
-- LEFT JOIN titles t ON t.ID = adv.titleID
);
SELECT _ FROM users2 很快,但是如果我添加一个 ORDER BY lastName, firstName,大约需要 25 秒才能得到响应。
以下是 *EXPLAIN SELECT * FROM users2* 命令的结果:
我还(重新)创建了以下索引:
ALTER TABLE addresses ADD INDEX (Countries_ID);
ALTER TABLE addresses ADD INDEX (States_ID);
ALTER TABLE addresses_have_persons ADD INDEX (Persons_ID);
ALTER TABLE languages ADD INDEX (name);
ALTER TABLE persons_information ADD INDEX (addressID);
ALTER TABLE persons_information ADD INDEX (address2ID);
ALTER TABLE persons_information ADD INDEX (address3ID);
ALTER TABLE persons_information ADD INDEX (advisorID);
我认为问题的一个原因是 person_language 视图创建如下:
CREATE OR REPLACE VIEW persons_language AS
(SELECT lp.Persons_ID AS ID
, GROUP_CONCAT(DISTINCT l.name ORDER BY l.name SEPARATOR ', ') AS languages
FROM languages l
INNER JOIN languages_have_persons lp ON l.ID = lp.Languages_ID
GROUP BY lp.Persons_ID);
编辑 3: 对于那些感兴趣的人,我为 persons_language 视图添加了 EXPLAIN:
编辑 4: 今天的数据库会议结束后,我们决定删除所有与地址信息相关的对象并重新创建视图
CREATE OR REPLACE VIEW `users2` AS
(SELECT ac.username
, ac.password
, p.firstName
, p.lastName
, ac.eMail AS email
, pl.languages
, pi.description
, ac.Persons_ID AS ID
, pi.phone1
, pi.phone2
, p.status
, pi.publicMail
, adv.name AS Betreuer
FROM accounts ac
INNER JOIN persons p ON ac.Persons_ID = p.ID
INNER JOIN persons_information pi ON p.ID = pi.ID
INNER JOIN persons_language pl ON p.ID = pl.ID
INNER JOIN advisors adv ON pi.advisorID = adv.ID
WHERE ac.password IS NOT NULL
);
我还用
创建了一个索引CREATE INDEX LanguagesPersonsIndex ON `languages_have_persons` (`Languages_ID`, `Persons_ID`);
EXPLAIN 命令显示新索引正在使用中,并且在带有 ORDER BY 子句的 SELECT 和新索引之后的延迟,较小的视图约为 18 秒。这是新的结果: 我的问题是:我还能做些什么来提高性能?
【问题讨论】:
标签: mysql sql views query-optimization