【发布时间】:2015-01-15 20:43:41
【问题描述】:
我们有一个包含定期查询的事件表(如日历事件的开始和结束时间):
TABLE event (
`id` varchar(32) NOT NULL,
`start` datetime,
`end` datetime,
`derivedfrom_id` varchar(32),
`parent_id` varchar(32) NOT NULL
)
-
parent_id指向提供一些附加信息的日历表。 - 一些事件是从另一个事件创建的,因此通过
derivedfrom_id列有一个指向该“源”事件的引用。
在检索一组事件时,我们通常通过日期(start/end)和日历(parent_id)进行查询,并通过limit限制结果数量进行分页。
我们现在面临的问题:有时我们需要将用户的相关事件合并到一个单一的表示中。所以我们进行正常的查询
SELECT id, start, parent_id
FROM event
WHERE parent_id in (<list of calendars>)
AND start >= 'some date'
LIMIT x
...然后过滤掉原始事件,因为衍生物具有不同的信息并且无论如何都引用它们的起源。
您可能已经看到(比我们更早),我们在过滤之前进行了限制,因此收到了一组比我们最初预期的基数更小的事件,即结果数低于“x”之后过滤。
我唯一能想到的就是复制查询并进行子选择:
SELECT id, start, parent_id
FROM event
WHERE parent_id in (<list_of_calendars>)
AND start >= 'some date'
AND (/* the part below duplicates the previous conditions */
derivedfrom_id is not null
or id not in (
SELECT derivedfrom_id
FROM event
WHERE parent_id in (<list_of_calendars>)
AND start >= 'some date'
AND derivedfrom_id is not null
)
)
LIMIT x
但我几乎不相信这是做到这一点的唯一方法。特别是,因为我们的查询要复杂得多。
有没有更好的办法?
示例数据
(根据评论中的要求)
鉴于这三个事件:
│ *ID* │ *DERIVEDFROM_ID* │ *PARENT_ID* │ *START*
├──────┼──────────────────┼─────────────┼─────────────────
│ 100 │ - │ A │ 2014-11-18 15:00
│ 101 │ 100 │ B │ 2014-11-18 15:00
│ 150 │ - │ A │ 2014-11-20 08:00
...限制为 2,我想获取事件 101 和 150。
相反,使用当前方法:
- 限制为 2 的查询导致事件 100 和 101
- 过滤后,丢弃事件100,只剩下101个事件
关于预期答案的说明
上面的 SQL 实际上是从使用 JPA 的 Java 应用程序生成的。我目前的解决方案是生成一个 where 子句并复制它。如果有一些通用的 JPA 特定的东西,我将不胜感激。
【问题讨论】:
-
一些样本数据和期望的结果将有助于澄清关系
-
事件可以从派生事件派生吗?
-
关于您的示例:您正在搜索日历 A 和 B,并且您正在过滤掉第 100 行,因为第 101 行已经存在?如果您只想搜索 A 怎么办?你想返回 100 和 150?
-
您是否尝试过您的方法?我认为您的查询中的口头描述和实现的逻辑之间存在差异,因为您的查询实际上会过滤掉 derivatives 并保留其原件。它可能会保留与其他标准不匹配的事件的衍生品(例如,不匹配日期范围)。也许您实际上想要
id not in (SELECT derivedfrom_id ...)而不是derivedfrom_id not in (SELECT id ...),尽管您需要在子查询中过滤掉NULL。 -
也许我不明白你的问题,但你接受的答案对我来说似乎很复杂。如果在上面的列表中添加了另一个事件,id = 102 并且derivedfrom_id = 100,查询的输出应该是什么? (101, 150) 还是 (101, 102, 150)?或者也许是 (102, 150)?
标签: mysql sql performance