所以我正在开展一个数据挖掘项目,我们正在研究代码元素及其与这些事物的关系和变化。我们想要的是询问一些关于相关元素改变频率的问题。我已将其设置为视图,但运行时间为10分钟。我认为问题在于我必须进行大量的减法,连接和字符串比较来比较条目(对于我们的窗口大小),但我不知道解决这个问题的好方法。查询看起来像
select aw.same
, rw.k
, count(distint concat_ws(',', r1.id, r2.id)) as num
from deltamethoddeclaration dmd1
join revision r1
on r1.id=FKrevID
join methodinvocation mi
on mi.FKcallerID = dmd1.FKMDID
join deltamethoddeclaration dmd2
on mi.FKcalleeID = dmd2.FKMDID
join revision r2
on r2.id = dmd2.FKrevID
join revisionwindow rw
join authorwindow aw
where (dmd1.FKrevID - dmd2.FKrevID) < rw.k
and (dmd2.FKrevID - dmd1.FKrevID) < rw.k
and case aw.same
when 1 then
r1.author = r2.author
when 0 then
r1.author <> r2.author
else
1=1
end
group by aw.same
, rw.k
;
好的,所以revisionwindow存储了我们感兴趣的修订版窗口(10,20,50,100),并且作者窗口存储了我们想要的作者类型(相同,不同,不关心)。问题的一部分是,我们可以使用不同元素匹配的相同修订对,因此我能想到的唯一的黑客就是丑陋的计数(不同的concat())。这应该返回一个包含12行的表,每个表对应一个作者和修订版窗口的组合。 'num'下的条目是以指定方式相关的唯一修订对(在这种情况下,两种更改方法和一种方法都调用另一种)。它工作得很好,它只是疯狂的慢(约10分钟的运行时间)。我基本上都在寻求任何建议或帮助,以便在不牺牲准确性的情况下使这项工作更好。
答案 0 :(得分:1)
其中(dmd1.FKrevID-dmd2.FKrevID)&lt; rw.k
对此语句最具破坏性的是小于运算符<
而不是算术运算。 B树不能使用它,并且每次都会强制进行全表扫描。 Gory详细说明了为什么这样做:http://explainextended.com/2010/05/19/things-sql-needs-determining-range-cardinality/
我怀疑后端可以优化您的CASE
语句,<>
运算符会遇到与上述相同的问题。我会考虑加入=
运算符的方法,可能会破坏查询并使用UNION
语句,因此您始终可以使用索引。
您没有使用EXPLAIN
。您需要开始使用它来优化查询。您不知道正在使用哪些索引,哪些索引没有使用,或者您的条件是否具有足够的选择性甚至是有用的(如果它不是非常有选择性,请参阅最后一点)http://dev.mysql.com/doc/refman/5.0/en/explain.html
由于这是一个数据挖掘应用程序,因此您有很好的机会使用中间值的临时表。由于数据可能会定期(甚至可能只有一次!)进行转储,因此很容易经常重建长时间运行的临时表,而不会冒数据损坏的风险(或者因为您在寻找聚合模式时无关紧要) 。)
我已经开始运行超过60分钟的查询,并通过构建缓存硬件的临时表将它们减少到不到100毫秒(即时)。如果你不能使用上面的任何一个想法,这可能是最低的水果。采取所有'硬件' - 案例连接和非平等连接,并在一个地方做。然后在你的临时表中添加一个索引:-)诀窍是让它足够通用,你可以查询临时表,这样你仍然可以灵活地提出不同的问题。
答案 1 :(得分:0)
我怀疑两个连接(join revisionwindow rw
)和(join authorwindow aw
)没有ON条件但是使用WHERE,导致这个。
这两张表有多少条记录? MySQL可能首先在这些上进行CROSS JOIN,然后才检查复杂(WHERE)条件。
但请发布EXPLAIN
的结果。
- EDIT--
哎呀,我错过了你的最后一段,解释说这两个表有4行和3行。
你可以试试这个: (已取代concat的地方 并且where子句已被移动为JOIN ON ...)
select aw.same
, rw.k
, count(distint r1.id, r2.id) as num
from deltamethoddeclaration dmd1
join revision r1
on r1.id = dmd1.FKrevID
join methodinvocation mi
on mi.FKcallerID = dmd1.FKMDID
join deltamethoddeclaration dmd2
on mi.FKcalleeID = dmd2.FKMDID
join revision r2
on r2.id = dmd2.FKrevID
join revisionwindow rw
on (dmd1.FKrevID - dmd2.FKrevID) < rw.k
and (dmd2.FKrevID - dmd1.FKrevID) < rw.k
join authorwindow aw
on case aw.same
when 1 then
r1.author = r2.author
when 0 then
r1.author <> r2.author
else
1=1
end
group by aw.same
, rw.k
;