2017-07-17 66 views
0

我是MySQL的性能優化新手&需要您的幫助,以獲得有關在我們的設計中稍後替換表的視圖。MySQL中的有序視圖的性能問題

表要被替換被稱爲用戶和具有下列屬性: The structure of the TABLE users 該users2視圖具有下列屬性: The structure of the VIEW users2

當我執行正常上兩個對象選擇,它們在同一時間作出迴應:

SELECT * 
FROM `users` 

SELECT * 
FROM `users2` 

但這些查詢的有序版本導致不同PERFORMA NCE:該表是一個慢一點(需要不到兩秒鐘),認爲需要十倍左右這個時間:

SELECT * 
FROM `users` 
ORDER BY `lastName`, `firstName` 

SELECT * 
FROM `users2` 
ORDER BY `lastName`, `firstName` 

要查清原因,我讓EXPLAIN了兩點意見: EXPLAIN SELECT * FROM users EXPLAIN SELECT * FROM users2

顯然,一個上表 '一個' 上Countries_ID屬性(地址)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 
); 

The structure of VIEW users2 注意3:雖然很多在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; 

確實包含只有最必要的東西,現在的結構如下: New TABLE persons

新表persons_information承載所有附加信息: TABLE 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姓氏,名字,需要約25秒獲得響應。

這裏是* EXPLAIN SELECT *從users2結果*命令: EXPLAIN SELECT * FROM users2

這裏爲其他命令: EXPLAIN SELECT * FROM users2 ORDER BY lastName, firstName

我也(重新)創建下列指標:

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); 

我想一個原因問題是創建如下persons_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 SELECT * FROM persons_language

編輯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子句與新的,更小的觀點是約18秒。下面是新的結果: EXPLAIN SELECT * FROM users2 ORDER BY lastName, firstName 我的問題是:我可以做更多,以提高性能?

回答

1

關鍵的故障必須是問題。 但根據連接表的數據量,它會反正較慢。 嘗試到:

  • 對所有用於建立關係的屬性實施KeyIndexes。 (ap.Addresses_ID,a.Countries_ID,p.addressID,AP。Persons_ID,a.States_ID,p.advisorID)。
  • 在所有'ID'列上聲明PK。
  • 請勿在視圖構造中使用ORDER或GROUP。
  • 聲明最常用於搜索,排序或分組的屬性的密鑰索引。

提示:'INNER'(INNER JOIN)不是必需的。相同的「加入」

您的視圖「persons_language」會是這樣更好:

SELECT lp.Persons_ID AS ID, GROUP_CONCAT(DISTINCT l.name ORDER BY l.name SEPARATOR ', ') AS languages 
FROM languages_have_persons lp 
JOIN languages l ON l.ID = lp.Languages_ID 
GROUP BY lp.Persons_ID; 

這是因爲「FROM」條款更合適,「加入」的前處理「WHERE」條款。

你可能會提高你的mysql內存和緩存配置。 看我的MySQL服務器的配置(運行與體重表和視圖的ERP):

join_buffer_size= 256M 
key_buffer = 312M 
key_buffer_size = 768M 
max_allowed_packet = 160M 
thread_stack = 192K 
thread_cache_size = 8 
query_cache_limit = 64M 
innodb_buffer_pool_size = 1512M 
table_cache = 1024M 
read_buffer_size = 4M 
query_cache_size = 768M 
query_cache_limit = 128M 
+0

謝謝你的回覆@Renato Tarso!不幸的是,我在一個必要的視圖中有一個ORDER BY。看到上面的問題編輯。所有的訂單/分組/關係屬性都是關鍵。 – Sae1962

+0

「...是主鍵」(當然,沒有意見顧問和persons_language主鍵) – Sae1962

+0

@ Sae1962,檢查我的答案變化。我希望這是有用的。祝你好運。 –

0
SELECT * 
FROM `users` 
ORDER BY `lastName`, `firstName` 

需求

INDEX(last_name, first_name) -- in that order 

謹防VIEWs;一些VIEWs優化得好,有些則沒有。

請爲addressesaddresses_have_persons提供SHOW CREATE TABLE

persons_language中,爲什麼需要DISTINCT?它沒有PRIMARY KEY(person, language)(或以相反的順序)?我們來看看SHOW CREATE TABLE

請爲您要討論的任何查詢提供EXPLAIN