基于浏览网页,我提出了两种计算表格“Table1”中记录的方法。计数器字段根据日期字段“TheDate”递增。它通过将记录与较旧的TheDate值相加来实现。此外,使用单独的计数器计算具有复合字段(Field1,Field2)的不同值的记录。 Field3只是一个信息字段,包含在内以增加意识,不会影响计数或记录如何分组以进行计数。
方法1:使用corrrelated子查询
null
方法2:使用加入和分组
SELECT MainQuery.Field1,
MainQuery.Field2,
MainQuery.Field3,
MainQuery.TheDate,
(
SELECT SUM(1) FROM Table1 InnerQuery
WHERE InnerQuery.Field1 = MainQuery.Field1 AND
InnerQuery.Field2 = MainQuery.Field2 AND
InnerQuery.TheDate <= MainQuery.TheDate
) AS RunningCounter
FROM Table1 MainQuery
ORDER BY MainQuery.Field1,
MainQuery.Field2,
MainQuery.TheDate,
MainQuery.Field3
方法2中没有内部查询本身,但我使用表别名InnerQuery,以便可以绘制方法1的现成的parellel。角色是一样的;表1的第二个实例用于累积记录的计数,这些记录的TheDate小于MainQuery(表1的第一个实例)中具有相同Field1和Field2值的任何记录的计数。
请注意,在方法2中,字段3包含在Group-By子句中,即使我说它不会影响记录的分组方式以进行计数。这仍然是正确的,因为计数是使用InnerQuery中的匹配记录完成的,而GROUP By适用于MainQuery中的字段3.
我发现方法1明显更快。我对此感到惊讶,因为它使用了相关的子查询。我想到一个相关子查询的方式是它是为MainQuery中的每个记录执行的(无论是否在优化后在实践中完成)。另一方面,方法2不会反复运行内部查询。但是,内连接在InnerQuery中仍然有多条记录匹配MainQuery中的每条记录,因此从某种意义上说,它处理类似的复杂顺序。
这种速度差异是否有一个不错的直观解释,以及选择时基积累方法的最佳实践或考虑因素?
我已将此发布到
答案 0 :(得分:0)
事实上,我认为最简单的方法是:
SELECT MainQuery.Field1,
MainQuery.Field2,
MainQuery.Field3,
MainQuery.TheDate,
COUNT(*)
FROM Table1 MainQuery
GROUP BY MainQuery.Field1,
MainQuery.Field2,
MainQuery.Field3,
MainQuery.TheDate
ORDER BY MainQuery.Field1,
MainQuery.Field2,
MainQuery.TheDate,
MainQuery.Field3
(顺序by不需要获取相同的数据,只是为了订购它。换句话说,删除它不会改变返回的每一行的数量或内容,只是它们返回的顺序。)
您只需要指定一次表。不需要进行自联接(将表连接到自己的查询)。两个查询的性能将取决于我不知道的一大堆事情 - 主键是什么,行数,可用内存量等等。
答案 1 :(得分:0)
首先,您的体验非常有意义。我不确定为什么你需要更多直觉。我想你在某个地方学到了相关的子查询是邪恶的。好吧,就像有些事情我们教孩子们真的很糟糕(&#34;当步行标志不是绿色时不要过马路#);结果并不是那么糟糕,同样的是相关子查询的确如此。
最简单的直觉是不相关的子查询必须聚合表中的所有数据。相关版本只需聚合匹配字段,但必须反复进行。
要为其添加数字,假设您有1,000行,每组10行。输出为100行。第一个版本执行100个聚合,每个聚合10行。第二个进行1000行的聚合。那么,聚合通常以超线性方式(O(n log n),技术上)进行缩放。这意味着10个记录的100个聚合所花费的时间少于1000个记录的1个聚合。
你要求直觉,所以上面提供了一些直觉。有两个方面存在着无数的警告。例如,相关子查询可能能够更好地利用聚合的索引。并且,这两个查询不相同,因为正确的连接将是LEFT JOIN
。
答案 2 :(得分:0)
实际上,我在原帖中错了。内连接比相关子查询更快。但是,相关子查询能够在生成结果记录时显示其结果记录,因此它看起来更快。
作为一种好奇心,我发现如果相关的子查询方法被修改为使用sum(-1)而不是sum(1),则返回的记录数似乎与N-3不同到N(其中N是正确的数字,即表1中的记录数)。我不确定这是否是由于Access急于显示初始记录或什么不是的一些不当行为。
虽然看起来INNER JOIN赢得了一场失败,但仍存在一个重大的阴险警告。如果GROUP BY字段不能唯一地区分Table1中的每个记录,那么您将不会为Table1的每个记录获得单独的SUM。想象一下,GROUP BY字段值的特定组合匹配(例如)表1中的THREE记录。然后,您将获得所有的单个SUM。问题是,MainQuery中这三条记录中的每个还匹配InnerQuery中相同记录的所有 3,因此InnerQuery中的那些实例会多次计数。 非常阴险(我发现)。
所以看起来子查询可能是要走的路,鉴于上述重复性问题(上面的第2段),这是非常令人不安的。这是一个严重的问题,应该让任何脊椎发抖。我正在研究的另一个可能的解决方案是通过选择感兴趣的字段将MainQuery转换为子查询,并在INNER使用InnerQuery加入结果之前对它们进行DISTINCTifying。