2011-06-27 63 views
1

我通常在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 

编辑:Explain输出

"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" 
+2

临时表在哪里? – MPelletier

+0

你为什么说这是复制表格?你得到什么确切的信息? – MPelletier

+0

我运行它,并在它说它正在复制到一个临时表后显示在heidisql进程列表中。 – davidahines

回答

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 

UPDATE

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

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

batch_log.userid也是如此。

+0

这一切都是最有帮助的,谢谢你的详细回复。 – davidahines

+0

@dah - 不客气! –

+0

虽然我有点不明白你到达那里。有没有一本书或你会推荐阅读的东西,以便我能更好地理解这一点? – davidahines