我正在尝试将一些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秒,并不是真的可以接受。
我知道观点不会带来任何性能提升,而且我已将我能想到的每一列编入索引。 你对我有什么建议吗?
答案 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脚本最长执行时间。