MySQL中一个非平凡视图的性能问题

时间:2017-07-13 12:40:40

标签: mysql sql

我尝试了很长时间来创建一个工作视图,如果没有寻求帮助就不可能。但现在,视图存在并使用

创建
CREATE OR REPLACE VIEW users2 AS (

SELECT DISTINCT p.username
    , p.password
    , p.firstName
    , p.lastName
    , 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
    , p.advisorID
    , (SELECT DISTINCT CONCAT_WS(' ', (SELECT t.title
                                    FROM titles AS t
                                    WHERE p1.titleID = t.ID), p1.firstName, p1.lastName) AS name
        FROM persons p1, titles t
        WHERE (p1.titleID IS NULL OR p1.titleID = t.ID)
          AND p1.ID = p.advisorID) AS Betreuer
FROM addresses a, addresses_have_persons ap, countries c, persons p, states s
    , persons_language AS pl
WHERE a.ID = addressID
  AND a.Countries_ID = c.ID
  AND a.States_ID = s.ID
  AND ap.Addresses_ID = a.ID
  AND ap.Persons_ID = p.ID
  AND p.ID = pl.ID);

它应该替换一个名为'users'的类似表。要在我的本地MySQL上显示“用户”表最多需要两秒钟,并显示19条记录。要打开'users2'视图,显示相同数量的记录,但主表'人'中约有150条记录,大约需要15秒。

我在这里看到一个性能问题。您是否知道如何改进创建视图'users2'的SELECT?

我检查了子选择

SELECT DISTINCT CONCAT_WS(' ', (SELECT t.title
                                    FROM titles AS t
                                    WHERE p1.titleID = t.ID), p1.firstName, p1.lastName) AS name
    FROM persons p1, titles t
    WHERE (p1.titleID IS NULL OR p1.titleID = t.ID)
      AND p1.ID = p.advisorID

它会在一秒钟内响应。访问视图 persons_language 大约需要三秒钟。

提前谢谢!

EXPLAIN输出:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY ap  ALL NULL    NULL    NULL    NULL    19      
1   PRIMARY p   eq_ref  PRIMARY PRIMARY 4   test_apptest.ap.Persons_ID  1   Using where
1   PRIMARY a   ALL PRIMARY NULL    NULL    NULL    4   Using where; Using join buffer (flat, BNL join) 
1   PRIMARY s   eq_ref  PRIMARY PRIMARY 4   test_apptest.a.States_ID    1   
1   PRIMARY c   eq_ref  PRIMARY PRIMARY 4   test_apptest.a.Countries_ID 1   Using index 
1   PRIMARY <derived3>  ref key0    key0    5   test_apptest.ap.Persons_ID  10
1   PRIMARY padvisor    ALL NULL    NULL    NULL    NULL    146 Using where; Using join buffer (flat, BNL join) 
1   PRIMARY t   eq_ref  PRIMARY PRIMARY 4   test_apptest.padvisor.titleID   1   Using where 
3   DERIVED lp  ALL NULL    NULL    NULL    NULL    296 Using filesort  
3   DERIVED l   eq_ref  PRIMARY PRIMARY 4   test_apptest.lp.Languages_ID    1

1 个答案:

答案 0 :(得分:1)

在我看来,你可以像这样重写你的查询:

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
    , p.advisorID
    , CONCAT_WS(' ', t.title, padvisor.firstName, padvisor.lastName) AS Betreuer
FROM addresses a, addresses_have_persons ap, countries c, persons p, states s
    , persons_language AS pl
LEFT JOIN persons padvisor ON padvisor.ID = p.advisorID
LEFT JOIN titles t ON t.ID = padvisor.titleID 
WHERE a.ID = p.addressID
  AND a.Countries_ID = c.ID
  AND a.States_ID = s.ID
  AND ap.Addresses_ID = a.ID
  AND ap.Persons_ID = p.ID
  AND p.ID = pl.ID;

请注意

  • 当您的架构正确规范化时,您不应该需要DISTINCT。
  • ANSI SQL Standard&#39; 92中引入的连接语法更具可读性。您可以将查询完全转换为JOIN语法。

对于下一步,我们需要EXPLAIN <your_query>;的结果和表格的create语句,以便我们了解您的索引等等。

修改 这是&#34;现代&#34;中的相同查询。语法(25岁的东西不能真正现代,但我使用的语法仍然较旧):

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
    , CONCAT_WS(' ', t.title, p2.firstName, p2.lastName) 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 persons p2 ON p2.ID = p2.advisorID
LEFT JOIN titles t ON t.ID = p2.titleID;