如何提高 MySQL 的性能或查询执行时间?

Ash*_*jar 0 mysql performance optimization query-performance

这是我的查询:

SELECT          a.z_companyid_pk "z_companyid_pk"      ,
                a.company_name "Client"                ,
                a.display_name "Display_Name"          ,
                a.z_parentcompanyid_fk "Parent_Company",
                a.z_resellerid_fk "Reseller"           ,
                (SELECT company_name
                FROM    company_mst
                WHERE   z_companyid_pk= a.z_resellerid_fk
                )
                "Reseller_name",
                (SELECT IF(COUNT(*)>=1,"YES","NO")
                FROM    webprofile
                WHERE   z_boxid_fk IN
                        (SELECT z_boxid_pk
                        FROM    box_mst
                        WHERE   z_companyid_fk=a.z_companyid_pk
                        )
                )
                "V1_Website",
                (SELECT IF(COUNT(*)>=1,"YES","NO")
                FROM    webapp_mst
                WHERE   z_companyid_fk=a.z_companyid_pk
                )
                "V2_Website",
                (SELECT IF(COUNT(*)>0,"YES","NO")
                FROM    widget_mst
                WHERE   widget_status=1
                AND     type IN("templated-menu",
                                "menus")
                AND     z_companyid_fk=a.z_companyid_pk
                )
                "Widgets_with_my_menu",
                (SELECT IF(COUNT(imagehtml)>0,"YES","NO")
                FROM    image_mst
                WHERE   LENGTH(imagehtml)>0
                AND     z_companyid_fk   =a.z_companyid_pk
                )
                "HTML_menus",
                (SELECT         MAX(login_datetime)
                FROM            loginlog_mst a
                                LEFT OUTER JOIN contact_mst b
                                ON              a.z_contactid_fk=b.z_contactid_pk
                WHERE           b.z_companyid_fk                =a.z_companyid_pk
                )
                "LCI"                    ,
                k.z_boxid_pk "DMB_Box_ID",
                k.box_name               ,
                (SELECT box_lastcheck
                FROM    box_online
                WHERE   z_boxid_fk=k.z_boxid_pk
                )
                "LCI_last_Checked_in_Date",
                (SELECT websitelink
                FROM    company_profile
                WHERE   z_companyid_fk=a.z_companyid_pk
                )
                "Website",
                (SELECT company_email
                FROM    company_profile
                WHERE   z_companyid_fk=a.z_companyid_pk
                )
                "Primary_Contact_Email"                                                          ,
                                concat(a.company_address_line1,a.company_address_line2) "address",
                (SELECT city_name
                FROM    city_mst
                WHERE   z_cityid_pk = a.z_cityid_fk
                )
                "city",
                (SELECT state_name
                FROM    state_mst
                WHERE   z_stateid_pk = a.z_stateid_fk
                )
                "Province" ,
                (SELECT country_name
                FROM    country_mst
                WHERE   z_countryid_pk=z_countryid_fk
                )
                "country_name"                        ,
                a.company_postalcode "zip_postal_code",
                (SELECT telephone
                FROM    company_profile
                WHERE   z_companyid_fk=a.z_companyid_pk
                )
                "company_telephone"   ,
                a.z_timezoneid_fk     ,
                b.timezone "time_Zone",
                (SELECT facebooklink
                FROM    company_profile
                WHERE   z_companyid_fk=a.z_companyid_pk
                )
                "facebook",
                (SELECT twitterlink
                FROM    company_profile
                WHERE   z_companyid_fk=a.z_companyid_pk
                )
                "twitter",
                (SELECT    bizurl
                FROM       user_settings us
                           INNER JOIN asset_mst am
                           ON         (
                                                 us.userid=am.userid
                                      )
                WHERE      us.isiteid       =1
                AND        am.z_companyid_fk=a.z_companyid_pk
                )
                "Yelp",
                (SELECT    bizurl
                FROM       user_settings us
                           INNER JOIN asset_mst am
                           ON         (
                                                 us.userid=am.userid
                                      )
                WHERE      us.isiteid       =2
                AND        am.z_companyid_fk=a.z_companyid_pk
                )
                "Urbanspoon",
                (SELECT    bizurl
                FROM       user_settings us
                           INNER JOIN asset_mst am
                           ON         (
                                                 us.userid=am.userid
                                      )
                WHERE      us.isiteid       =3
                AND        am.z_companyid_fk=a.z_companyid_pk
                )
                "Trip_Advisor",
                (SELECT    bizurl
                FROM       user_settings us
                           INNER JOIN asset_mst am
                           ON         (
                                                 us.userid=am.userid
                                      )
                WHERE      us.isiteid       =4
                AND        am.z_companyid_fk=a.z_companyid_pk
                )
                "Citysearch",
                (SELECT    bizurl
                FROM       user_settings us
                           INNER JOIN asset_mst am
                           ON         (
                                                 us.userid=am.userid
                                      )
                WHERE      us.isiteid       =5
                AND        am.z_companyid_fk=a.z_companyid_pk
                )
                "Open_Table",
                (SELECT    bizurl
                FROM       user_settings us
                           INNER JOIN asset_mst am
                           ON         (
                                                 us.userid=am.userid
                                      )
                WHERE      us.isiteid       =6
                AND        am.z_companyid_fk=a.z_companyid_pk
                )
                "ZAGAT",
                (SELECT    bizurl
                FROM       user_settings us
                           INNER JOIN asset_mst am
                           ON         (
                                                 us.userid=am.userid
                                      )
                WHERE      us.isiteid       =32
                AND        am.z_companyid_fk=a.z_companyid_pk
                )
                "Zomato"                           ,
                d.z_contactid_fk "Email_contact_ID",
                d.username "Email_User_Name"       ,
                d.contact_firstname                ,
                d.contact_lastname                 ,
                d.status                           ,
                (SELECT MAX(login_datetime)
                FROM    loginlog_mst
                WHERE   z_contactid_fk=d.z_contactid_fk
                )
                "last_login_date",
                (SELECT GROUP_CONCAT(groupname)
                FROM    contact_group_mst
                WHERE   z_companyid_fk=a.z_companyid_pk
                )
                "group_name"
FROM            company_mst a
                LEFT OUTER JOIN timezone_mst b
                ON              a.z_timezoneid_fk=b.z_timezoneid_pk
                LEFT OUTER JOIN company_profile c
                ON              a.z_companyid_pk=c.z_companyid_fk
                LEFT OUTER JOIN
                                (SELECT         v.z_contactid_fk   ,
                                                v.z_companyid_fk   ,
                                                w.username         ,
                                                w.contact_firstname,
                                                w.contact_lastname ,
                                                IF(contact_wtaccess=1,"Veryfied","Not Veryfied") "status"
                                FROM            priviledge_mst v
                                                LEFT OUTER JOIN contact_mst w
                                                ON              v.z_contactid_fk=w.z_contactid_pk
                                WHERE           w.type                         <>"Staff"
                                )
                                d
                ON              a.z_companyid_pk=d.z_companyid_fk
                LEFT OUTER JOIN
                                (SELECT    z_boxid_pk,
                                           box_name  ,
                                           asset_mst.z_companyid_fk
                                FROM       box_mst
                                           INNER JOIN asset_mst
                                           ON        (
                                                                 box_mst.userid_fk = asset_mst.userid
                                                      )
                                WHERE      asset_mst.status = 0
                                AND        type             ="menubox"
                                )
                                k
                ON              a.z_companyid_pk=k.z_companyid_fk
WHERE           a.status                       <> 0
AND             a.z_companyid_pk IN(101089,104001,103863)
ORDER BY        a.company_name;
Run Code Online (Sandbox Code Playgroud)

在我的远程 MySQL 服务器上执行此查询至少需要 1 分钟。由于我是 MySQL 的新手,我对优化查询不太了解,所以请通过建议一些技术或修改或我可以应用于此查询以提高性能的任何提示来帮助我。

And*_*y M 15

您的查询中至少有三个部分会或可能会从重写中受益:

  1. SELECT 子句中的这五个相关子查询基于相同的条件从同一个表中检索数据:

    (select websitelink from company_profile  where z_companyid_fk=a.z_companyid_pk) "Website",
    (select company_email from company_profile  where z_companyid_fk=a.z_companyid_pk) "Primary_Contact_Email",
    (select telephone from company_profile  where z_companyid_fk=a.z_companyid_pk) "company_telephone",
    (select facebooklink from company_profile  where z_companyid_fk=a.z_companyid_pk) "facebook", 
    (select twitterlink from company_profile  where z_companyid_fk=a.z_companyid_pk) "twitter", 
    
    Run Code Online (Sandbox Code Playgroud)

    您可以通过company_profile在主 FROM 子句中引入左连接并仅引用主 SELECT 中的列来重写它们。但是等等,你已经有了这样的连接:

    LEFT OUTER JOIN company_profile c on a.z_companyid_pk=c.z_companyid_fk 
    
    Run Code Online (Sandbox Code Playgroud)

    出于某种原因,您没有使用它。您可以通过像这样重写上面的五列来使用它:

    c.websitelink   AS "Website",
    c.company_email AS "Primary_Contact_Email",
    c.telephone     AS "company_telephone",
    c.facebooklink  AS "facebook", 
    c.twitterlink   AS "twitter", 
    
    Run Code Online (Sandbox Code Playgroud)

    AS关键字是不必要的。我使用它是因为在我看来它提高了可读性,但您可以随意省略它。)

  2. 这一系列相关的子查询也从同一个行集中提取数据,但每个子查询都有一个额外的条件,这使得这与前一个不同:

    (SELECT  bizurl FROM user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)  where  us.isiteid=1 and am.z_companyid_fk=a.z_companyid_pk ) "Yelp",
    (SELECT  bizurl FROM user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)  where  us.isiteid=2 and am.z_companyid_fk=a.z_companyid_pk ) "Urbanspoon",
    (SELECT  bizurl FROM user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)  where  us.isiteid=3 and am.z_companyid_fk=a.z_companyid_pk ) "Trip_Advisor",
    (SELECT  bizurl FROM user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)  where  us.isiteid=4 and am.z_companyid_fk=a.z_companyid_pk ) "Citysearch",
    (SELECT  bizurl FROM user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)  where  us.isiteid=5 and am.z_companyid_fk=a.z_companyid_pk ) "Open_Table",
    (SELECT  bizurl FROM user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)  where  us.isiteid=6 and am.z_companyid_fk=a.z_companyid_pk ) "ZAGAT",
    (SELECT  bizurl FROM user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)  where  us.isiteid=32 and am.z_companyid_fk=a.z_companyid_pk ) "Zomato",
    
    Run Code Online (Sandbox Code Playgroud)

    重写这些将需要的不仅仅是和外连接以保持相同的输出格式。

    首先这个加入

    user_settings us  INNER JOIN asset_mst am ON (us.userid=am.userid)
    
    Run Code Online (Sandbox Code Playgroud)

    可能返回这样的数据:

    ...  am.z_companyid_fk  us.isiteid  us.bizurl                ...
    ---  --------------     ----------  -----------------------  ---
    ...  some_comp_id       1           some-Yelp-URL            ...
    ...  some_comp_id       2           some-Urbanspoon-URL-URL  ...
    ...  some_comp_id       3           some-Trip_Advisor-URL    ...
    ...  some_comp_id       4           some-Citysearch-URL      ...
    ...  some_comp_id       5           some-Open_Table-URL      ...
    ...  some_comp_id       6           some-ZAGAT-URL           ...
    ...  some_comp_id       32          some-Zomato-URL          ...
    ...  ...                ...         ...                      ...
    
    Run Code Online (Sandbox Code Playgroud)

    但是您希望它们排成一行,如下所示:

    ...  am.z_companyid_fk  Yelp           Urbanspoon               Trip_Advisor           Citysearch           Open_Table          ZAGAT           Zomato
    ---  -----------------  -------------  -----------------------  ---------------------  -------------------  ------------------  --------------  ---------------
    ...  some_comp_id       some-Yelp-URL  some-Urbanspoon-URL-URL  some-Trip_Advisor-URL  some-Citysearch-URL  some-Open_Table-URL some-ZAGAT-URL  some-Zomato-URL
    ...  ...                ...            ...                      ...                    ...                  ...                 ...             ...
    
    Run Code Online (Sandbox Code Playgroud)

    像这样转动行的过程称为旋转。那么你

    • 旋转连接的结果(在 MySQL 中,您可以使用条件聚合来实现):

      SELECT
        am.z_companyid_fk,
        MAX( CASE WHEN us.isiteid= 1 THEN bizurl END ) AS "Yelp",
        MAX( CASE WHEN us.isiteid= 2 THEN bizurl END ) AS "Urbanspoon",
        MAX( CASE WHEN us.isiteid= 3 THEN bizurl END ) AS "Trip_Advisor",
        MAX( CASE WHEN us.isiteid= 4 THEN bizurl END ) AS "Citysearch",
        MAX( CASE WHEN us.isiteid= 5 THEN bizurl END ) AS "Open_Table",
        MAX( CASE WHEN us.isiteid= 6 THEN bizurl END ) AS "ZAGAT",
        MAX( CASE WHEN us.isiteid=32 THEN bizurl END ) AS "Zomato"
      FROM
        user_settings us
        INNER JOIN asset_mst am ON (us.userid=am.userid)
      GROUP BY
        am.z_companyid_fk
      
      Run Code Online (Sandbox Code Playgroud)
    • 在主 FROM 子句中与它们外部连接:

      LEFT JOIN
      (
        SELECT
          am.z_companyid_fk,
        …
        …
        …
        GROUP BY
          am.z_companyid_fk
      ) AS url ON url.z_companyid_fk=a.z_companyid_pk
      
      Run Code Online (Sandbox Code Playgroud)
    • 最后只引用主 SELECT 子句中的透视列名,而不是那些相关的子查询:

      url."Yelp",
      url."Urbanspoon",
      url."Trip_Advisor",
      url."Citysearch",
      url."Open_Table",
      url."ZAGAT",
      url."Zomato",
      
      Run Code Online (Sandbox Code Playgroud)
  3. 最后,本组中相关的子查询:

    (select if(count(*)>=1,"YES","NO") from webprofile where z_boxid_fk in(select z_boxid_pk from box_mst where z_companyid_fk=a.z_companyid_pk)) "V1_Website",
    (select if(count(*)>=1,"YES","NO") from webapp_mst where z_companyid_fk=a.z_companyid_pk) "V2_Website",
    (select if(count(*)>0,"YES","NO") from widget_mst where widget_status=1 and type in("templated-menu","menus") and z_companyid_fk=a.z_companyid_pk) "Widgets_with_my_menu",
    (select if(count(imagehtml)>0,"YES","NO") from image_mst where  length(imagehtml)>0 and  z_companyid_fk=a.z_companyid_pk)"HTML_menus",
    
    Run Code Online (Sandbox Code Playgroud)

    都具有相同的模式:它们都用于COUNT(*)确定是否显示YESNO。根据您使用的数据库引擎,这可能效率低下。改用 EXISTS 可能是一个更好的主意。所以,你可以像这样重写上面的内容:

    IF(EXISTS (select * from webprofile where z_boxid_fk in(select z_boxid_pk from box_mst where z_companyid_fk=a.z_companyid_pk)),       'YES', 'NO') AS "V1_Website",
    IF(EXISTS (select * from webapp_mst where z_companyid_fk=a.z_companyid_pk),                                                           'YES', 'NO') AS "V2_Website",
    IF(EXISTS (select * from widget_mst where widget_status=1 and type in('templated-menu','menus') and z_companyid_fk=a.z_companyid_pk), 'YES', 'NO') AS "Widgets_with_my_menu",
    IF(EXISTS (select * from image_mst  where length(imagehtml)>0 and z_companyid_fk=a.z_companyid_pk),                                   'YES', 'NO') AS "HTML_menus",
    
    Run Code Online (Sandbox Code Playgroud)

    或者,您可以在每种情况下YES只返回单词和一行(使用LIMIT 1),NO用 IFNULL 或 COALESCE替换可能的空结果:

    IFNULL( (select 'YES' from webprofile where z_boxid_fk in(select z_boxid_pk from box_mst where z_companyid_fk=a.z_companyid_pk) LIMIT 1),       'NO') AS "V1_Website",
    IFNULL( (select 'YES' from webapp_mst where z_companyid_fk=a.z_companyid_pk LIMIT 1),                                                           'NO') AS "V2_Website",
    IFNULL( (select 'YES' from widget_mst where widget_status=1 and type in('templated-menu','menus') and z_companyid_fk=a.z_companyid_pk LIMIT 1), 'NO') AS "Widgets_with_my_menu",
    IFNULL( (select 'YES' from image_mst where length(imagehtml)>0 and z_companyid_fk=a.z_companyid_pk LIMIT 1),                                    'NO') AS "HTML_menus",
    
    Run Code Online (Sandbox Code Playgroud)

可能还有其他值得关注的部分,但这三个对我来说是突出的。

总之,我只想补充一点,第一个要点中的重写肯定会改进您在问题中发布的查询。另外两个我不太确定,所以我建议你独立尝试/测试它们。