【发布时间】:2013-06-26 09:32:55
【问题描述】:
我有一张桌子(我们称之为audit),看起来像这样:
+--------------------------------------------------------------------------+
| id | recordId | status | mdate | type | relatedId |
+--------------------------------------------------------------------------+
| 1 | 3006 | A | 2013-04-03 23:59:01.275 | type1 | 1 |
| 2 | 3025 | B | 2013-04-04 00:00:02.134 | type1 | 1 |
| 3 | 4578 | A | 2013-04-04 00:04:30.033 | type2 | 1 |
| 4 | 7940 | C | 2013-04-04 00:04:32.683 | type1 | <NULL> |
| 5 | 3006 | D | 2013-04-04 00:04:32.683 | type1 | <NULL> |
| 6 | 4822 | E | 2013-04-04 00:04:32.683 | type2 | <NULL> |
| 7 | 3006 | A | 2013-04-04 00:06:54.033 | type1 | 2 |
| 8 | 3025 | C | 2013-04-04 00:06:54.033 | type1 | 2 |
...以及数百万行。还有一张我们称之为related的表:
+-------------+
| id | source |
+-------------+
| 1 | src_X |
| 2 | src_Y |
| 3 | src_Z |
| 4 | src_X |
| 5 | src_X |
...以及数十万行。
两个表上的列都比这些列多,但这就是我们描述问题所需的全部内容。 relatedId 列连接到 related 表。 recordId 也加入了另一个表,audit 中会有多个条目具有相同的recordId。
我正在尝试创建一个将产生以下输出的查询:
+-----------------+
| source | count |
+-----------------+
| src_X | 1643 |
| src_Y | 255 |
| NULL | 729 |
+-----------------+
计数是audit 中具有给定type(例如"type1")并且处于一组状态(例如"A", "B", "C")内的记录数,然后将这些状态从外部连接到@ 987654335@ 并按source 分组。
问题是我只想包含来自audit 中某个日期范围内的记录,并且我也只想加入从audit 到related 的每个在该范围内最旧的条目recordId。此外,我想忽略任何符合 type 和 status 条件的记录,但有一个比日期范围更早的 recordId 条目。
所以,从上面的示例数据中澄清一下:假设我想要type1 的类型和"A", "B", "C" 的状态值,日期范围为2013-04-04 到2013-04-05。第 2 行和第 4 行将包括在计数中。第 3 行被排除在外,因为它的 type 不正确。由于状态不正确,第 5 行被排除在外。第 6 行被排除,因为状态和类型都不正确。第 1 行被排除在外,因为它超出了日期范围。第 7 行也被排除在外,因为还有另一行(第 1 行)与具有相同 recordId 的状态和类型标准匹配,该 recordId 早于日期范围的开始。第 8 行被排除在外,因为第 8 行和第 2 行具有相同的recordId 并符合条件,但我们只计算范围内两者中最旧的记录。
换句话说,我只想计算给定recordId的条目第一次出现在表中并且在目标日期范围内。
我们提出了以下建议:
WITH data (recordId, id) AS (
SELECT a.recordId, MIN(a.id)
FROM audit a
WHERE a.status in ('A','B','C')
AND type = 'type1'
GROUP BY a.recordId
)
SELECT r.source, COUNT(*)
FROM data d
JOIN audit a ON d.id = a.id
LEFT JOIN related r ON a.relatedId = r.id
WHERE a.mdate >= '2013-04-04 00:00:00.000'
and a.mdate < '2013-04-05 00:00:00.000'
GROUP BY r.source
这将在 MSSQL Server 2008 上运行,目前依赖于审计表 ID 是自动生成的这一事实。由于 id 是在插入记录时生成的,并且 mdate 也是插入时间戳,并且记录一旦插入就永远不会更新,我认为这是可以的。该查询似乎在一组有限的测试数据上给出了正确的输出,但我希望得到第二个意见。
- 这个查询看起来正常吗?
- 可以提高性能吗?
【问题讨论】:
-
计算表表达式中的日期范围可能会提高性能。
-
好点。将
AND a.mdate < '2013-04-05 00:00:00.000'添加到计算表将有助于限制它返回的记录数。 -
为了提高查询性能也要注意索引。在 WHERE 子句字段上使用索引,加入字段,并再次测试性能。..
标签: sql sql-server query-performance