避免复制到临时表

时间:2011-06-27 17:36:16

标签: mysql sql optimization

我通常在java中完成大部分工作,我无法真正找到我在这里做的事情,导致它需要复制到桌面并死掉。

SELECT company.tblusers.userid, 
db.operations.id AS operation_id,
SUM(TIME_TO_SEC(db.batch_log.time_elapsed)) AS time_elapsed, 
SUM(db.tasks.estimated_nonrecurring + db.tasks.estimated_recurring) AS total_elapsed,
COUNT(db2.ncr_ncr.id) AS number_of_ncrs
FROM company.tblusers 
INNER JOIN db.operations 
INNER JOIN db.batch_log ON company.tblusers.userid = batch_log.userid 
INNER JOIN db.batches ON batch_log.batch_id = batches.id 
INNER JOIN db.tasks ON db.batches.id = db.tasks.batch_id
INNER JOIN db2.ncr_ncr ON company.tblusers.sugar_name = db2.ncr_ncr.employee
WHERE company.tblusers.departmentid = 8 
AND db.operations.id = db.batches.operation_id 
AND db.batches.id = db.tasks.batch_id 
AND db.batch_log.userid = company.tblusers.userid
AND db2.ncr_ncr.employee = company.tblusers.sugar_name 
GROUP by company.tblusers.userid, db.batches.operation_id

编辑:解释输出

"id";"select_type";"table";"type";"possible_keys";"key";"key_len";"ref";"rows";"Extra"
"1";"SIMPLE";"ncr_ncr";"ALL";NULL;NULL;NULL;NULL;"2700";"Using temporary; Using filesort"
"1";"SIMPLE";"batch_log";"ALL";NULL;NULL;NULL;NULL;"78026";""
"1";"SIMPLE";"tblusers";"eq_ref";"PRIMARY";"PRIMARY";"52";"ramses.batch_log.userid";"1";"Using where"
"1";"SIMPLE";"tasks";"ref";"Index 2";"Index 2";"38";"ramses.batch_log.batch_id";"2";""
"1";"SIMPLE";"batches";"eq_ref";"PRIMARY";"PRIMARY";"38";"ramses.tasks.batch_id";"1";"Using where"
"1";"SIMPLE";"operations";"eq_ref";"PRIMARY";"PRIMARY";"4";"ramses.batches.operation_id";"1";"Using where; Using index"

1 个答案:

答案 0 :(得分:8)

如果在对非索引的列组合进行分组时聚合值,则SQL引擎将创建临时表作为其正常运行的一部分,以便保存部分聚合的值。您需要为company.tblusers.useriddb.batches.operation_id的每个组合计算两个SUM和一个COUNT。必须存储这些值,因为很明显,没有包含这两列的索引,因为它们位于不同的表中。

我不知道它为什么会死,除非它实际上是因为COUNT聚合而将完整连接构建为临时表。

您可能只应将其作为相关子查询,而不是加入db2.ncr_ncr表。这可能需要更少的存储空间:

SELECT
        company.tblusers.userid,
        db.operations.id AS operation_id,
        SUM(TIME_TO_SEC(db.batch_log.time_elapsed)) AS time_elapsed,
        SUM(db.tasks.estimated_nonrecurring + db.tasks.estimated_recurring) AS total_elapsed,
        (SELECT COUNT(*) FROM db2.ncr_ncr WHERE db2.ncr_ncr.employee = company.tblusers.sugar_name) AS number_of_ncrs
FROM 
        company.tblusers
        INNER JOIN db.batch_log ON batch_log.userid = company.tblusers.userid
        INNER JOIN db.batches ON db.batches.id = db.batch_log.batch_id
        INNER JOIN db.operations ON db.operations.id = db.batches.operation_id
        INNER JOIN db.tasks ON db.tasks.batch_id = db.batch_log.batch_id
WHERE
        company.tblusers.departmentid = 8
GROUP BY 
        company.tblusers.userid,
        db.batches.operation_id 

<强>更新

根据解释计划结果,您没有查询可以在ncr_ncr上使用的任何索引。这是不好的。它实际上创建了一个表的新副本,它可以按employee排序,以便可以在合理的时间内进行连接。

即使该表不是很大(只有2700行),你仍然需要在db2.ncr_ncr.employee上放置一个索引(最好是相关的,如果系统的其余部分允许它),否则你的性能将会受苦受难。这个表足够小,制作和分类临时副本不应该是一个问题,但它仍然会损害你的表现。

batch_log.userid也是如此。