我怎样才能提高这个joomla查询的性能?

时间:2014-01-28 18:31:06

标签: mysql joomla2.5 database-performance

我正在尝试将一些joomla用户数据传递给Datatable(jQuery插件)。 涉及4个表

  • joo_users(~10k行),
  • joo_user_groups(约1.7k行),
  • joo_user_usergroup_map(~56k行),
  • joo_user_profiles(~1398k行)

现在的查询:

SELECT SQL_CALC_FOUND_ROWS
    a.id,
    a.name,
    MAX( IF(profiles.profile_key = 'profile.email', profiles.profile_value, NULL) ) AS email,
    MAX( IF(profiles.profile_key = 'profile.codice_agente', profiles.profile_value, NULL) ) AS codice_agente,
    MAX( IF(profiles.profile_key = 'profile.codice_agente_fisso', profiles.profile_value, NULL) ) AS codice_agente_fisso,
    MAX( IF(profiles.profile_key = 'profile.codice_agente_VAR', profiles.profile_value, NULL) ) AS codice_agente_VAR,
    MAX( IF(profiles.profile_key = 'profile.cellulare', profiles.profile_value, NULL) ) AS cellulare,
    (SELECT
       GROUP_CONCAT(DISTINCT b.title)
    FROM
       joo_user_profiles AS up
    LEFT JOIN
       joo_usergroups AS b ON REPLACE(up.profile_value, '"', '') = b.id
    WHERE
       up.profile_key LIKE 'profile.agenzia_%'
       AND up.user_id = a.id
       AND profile_value != '""') AS agenzia,
   GROUP_CONCAT(DISTINCT REPLACE(IF(profiles.profile_key LIKE 'profile.canale_%' AND profiles.profile_value = '1', profiles.profile_key, NULL),'profile.canale_','') ) AS canale,
   GROUP_CONCAT(DISTINCT IF(profiles.profile_key LIKE 'profile.area_%' AND profiles.profile_value != '""', profiles.profile_value, NULL))  AS area,
   (SELECT
        GROUP_CONCAT(DISTINCT b.title)
        FROM
           joo_user_profiles AS up
        LEFT JOIN
           joo_usergroups AS b ON REPLACE(up.profile_value, '"', '') = b.id
        WHERE
           up.profile_key LIKE 'profile.ruolo_%'
           AND up.user_id = a.id
           AND profile_value != '"0"') AS ruolo,
    GROUP_CONCAT(IF(profiles.profile_key LIKE 'profile.status_%' AND profiles.profile_value != '""', profiles.profile_value, NULL))  AS status

    FROM   `joo_users` as a
    LEFT JOIN joo_user_profiles AS profiles ON a.id = profiles.user_id

    GROUP BY id

    ORDER BY  id
          asc
    LIMIT 0, 20

这个野兽在生产服务器上需要40秒,并不是真的可以接受。

我知道观点不会带来任何性能提升,而且我已将我能想到的每一列编入索引。 你对我有什么建议吗?

2 个答案:

答案 0 :(得分:1)

我不知道为什么你需要calc_found_rows,但是把它放在那里。 至于查询,因为所有的group_concats主要是针对配置文件表和可选的用户组,所以我做了一个预查询(通过tmpGrpCat别名),它只为用户提供了相应的group_concat和max(),用于电子邮件,condice等元素...,单元格等我也在此预查询中包含了排除配置文件值不是“”的位置,因为对于您感兴趣的值,它似乎是一致的。

然后我在users表上做了一个简单的left-join来获取他们的id / name以及其余的聚合。这应该简化引擎,为每个profile_key LIKE(或相等)条件运行所有记录ONCE,按用户的ID对它们进行分组,然后准备好进行最外层的查询。

如果这样有效,请告诉我们性能改进。如果将来也可以帮助其他人使用性能技术。

SELECT SQL_CALC_FOUND_ROWS
      a.id,
      a.name,
      coalesce( tmpGrpCat.email, '' ) as email,
      coalesce( tmpGrpCat.codice_agente, '' ) as codice_agente,
      coalesce( tmpGrpCat.codice_agente_fisso, '' ) as codice_agente_fisso,
      coalesce( tmpGrpCat.codice_agente_VAR, '' ) as codice_agente_VAR,
      coalesce( tmpGrpCat.cellulare, '' ) as cellulare,
      coalesce( tmpGrpCat.AgTitle, '' )  as Agenzia,
      coalesce( tmpGrpCat.RuoloTitle, '' )  as ruolo,
      coalesce( tmpGrpCat.Canale, '' )  as Canale,
      coalesce( tmpGrpCat.Area, '' )  as Area,
      coalesce( tmpGrpCat.Status, '' )  as Status
   FROM   
      joo_users as a
         LEFT JOIN 
         ( SELECT 
                 up.user_id,
                 GROUP_CONCAT( DISTINCT IF( up.profile_key LIKE 'profile.agenzia_%', b.title, NULL )) AgTitle,
                 GROUP_CONCAT( DISTINCT IF( up.profile_key LIKE 'profile.ruolo_%', b.title, NULL )) RuoloTitle,
                 GROUP_CONCAT( DISTINCT IF( up.profile_key LIKE 'profile.canale_%' AND up.profile_value = '1', 
                    REPLACE( up.profile_key, 'profile.canale_',''), NULL)) AS canale,
                 GROUP_CONCAT( DISTINCT IF( up.profile_key LIKE 'profile.area_%', 
                    up.profile_value, NULL))  AS area,
                 GROUP_CONCAT( DISTINCT IF( up.profile_key LIKE 'profile.status_%', 
                    up.profile_value, NULL))  AS status,
                 MAX( IF( up.profile_key = 'profile.email', up.profile_value, NULL) ) AS email,
                 MAX( IF( up.profile_key = 'profile.codice_agente', up.profile_value, NULL) ) AS codice_agente,
                 MAX( IF( up.profile_key = 'profile.codice_agente_fisso', up.profile_value, NULL) ) AS codice_agente_fisso,
                 MAX( IF( up.profile_key = 'profile.codice_agente_VAR', up.profile_value, NULL) ) AS codice_agente_VAR,
                 MAX( IF( up.profile_key = 'profile.cellulare', up.profile_value, NULL) ) AS cellulare
              FROM 
                 joo_user_profiles AS up
                    LEFT JOIN joo_usergroups AS b 
                       ON REPLACE(up.profile_value, '"', '') = b.id
                    WHERE
                        ( up.profile_key LIKE 'profile.agenzia_%'
                       OR up.profile_key LIKE 'profile.ruolo_%' 
                       OR up.profile_key LIKE 'profile.canale_%'
                       OR up.profile_key LIKE 'profile.area_%' 
                       OR up.profile_key LIKE 'profile.status_%'
                       OR up.profile_key = 'profile.email'
                       OR up.profile_key = 'profile.codice_agente'
                       OR up.profile_key = 'profile.codice_agente_fisso'
                       OR up.profile_key = 'profile.codice_agente_VAR'
                       OR up.profile_key = 'profile.cellulare' )
                       AND up.profile_value != '""' 
                       AND up.profile_value != '"0"'
                    GROUP BY
                       up.user_id ) as tmpGrpCat
            ON a.id = tmpGrpCat.user_id
   ORDER BY  
      id asc
   LIMIT 
      0, 20

答案 1 :(得分:0)

由于您在Joomla中执行此查询,您可以尝试使用可以通过使用数据源缓存(对于查询结果)和ajax加载来处理大数据集的Joomla(http://wwww.tabulizer.com)的Tabulizer,因此只有第一个最初提取表的页面,仅在需要时提取其余数据。当然,查询需要至少执行一次才能填充缓存,因此您必须进一步改进它或增加可用的系统资源(PHP内存和最大执行时间)。这很可能是因为它在服务器上而不是在本地服务器上失败,因为大多数共享主机环境都有30秒的PHP脚本最长执行时间。