4

我有一个事件结果表,我需要为给定的玩家列表获取每个玩家最近的 n 个事件。

这是在 iOS 上,所以它需要很快。我查看了很多使用子查询或连接的 top-n-per-group 解决方案,但即使在 macbook pro 上,这些解决方案对于我的 100k 行数据集也运行缓慢。到目前为止,我的愚蠢解决方案是执行 6 个单独的查询,因为我最多只能运行 6 个玩家。它不是很慢,但必须有更好的方法,对吧?这是我现在正在做的事情的要点:

results_by_pid = {} 
player_ids = [1,2,3,4,5,6]
n_results = 6
for pid in player_ids:
  results_by_pid[pid] = exec_sql("SELECT * 
                                  FROM results
                                  WHERE player_id = #{pid}
                                  ORDER BY event_date DESC
                                  LIMIT n_events")

然后我继续我的快乐之路。但是我怎样才能把它变成一个单一的快速查询呢?

4

2 回答 2

1

这不会是一个很大的答案,但这里......

我发现让事情变得非常快可能涉及来自数据和模式本身的性质的想法。例如,搜索有序列表比搜索无序列表要快,但您必须预先支付设计和执行成本。

所以问问自己,你的数据上是否有任何自然分区可能会减少 SQLite 必须搜索的记录数量。您可能会问最近的 n 个事件是否属于特定时间段。它们都来自过去 7 天吗?最后一个月?如果是这样,那么您可以构建查询以在执行更复杂的搜索之前排除整个数据块。

此外,如果你不能让事情快速工作,你可以考虑 UX 诡计!很多工程师对他们的用户体验并不聪明。您的查询会作为视图控制器推送的结果运行吗?然后将事情从 PREVIOUS 视图控制器设置在后台线程中,并让它在 iOS 动画时工作。推送动画需要多长时间?.2 秒?您的用户在什么时候向应用程序(通过一些 UX 控件)指示playerids要查询的内容?只要他触摸那个按钮或 TVCell,您就可以预取一些数据。因此,如果您要做的总工作是O(n log n),这意味着您可以将其分解为O(n)O(log n)部分。

只是一些想法,而我避免自己努力工作。


更多想法

一个包含前 n 个插入的 id 的单独表怎么样?如果表的大小增长到 n 以上,您可以添加一个触发器来删除旧的 id。说..

CREATE TABLE IF NOT EXISTS recent_results
   (result_id INTEGER PRIMARY KEY, event_date DATE);
// is DATE a type? I don't know. you get the point

CREATE TRIGGER IF NOT EXISTS optimizer
   AFTER INSERT ON recent_results
   WHEN (SELECT COUNT(*) FROM recent_results) > N
   BEGIN
      DELETE FROM recent_results
      WHERE result_id = (SELECT result_id
                         FROM recent_results
                         WHERE event_date = MIN(event_date));
// or something like that. I have no idea if this will work,
// I just threw it together.

或者,您可以创建一个基于内存的临时表,在应用加载时填充该表,并在应用执行期间执行事务时保持最新。这样,您只需支付一次高昂的价格!

只是给你一些想法。要有创意,记住你通常可以定义你想要的数据结构和算法。祝你好运!

于 2013-03-14T16:52:10.470 回答
1

没有更好的办法。SQLite 中没有实现可能有帮助的 SQL 窗口函数。

SQLite 被设计为嵌入式数据库,其中大部分逻辑都保留在应用程序中。与应避免网络通信的客户端/服务器数据库相比,混合 SQL 命令和程序逻辑没有性能劣势。

一个不那么愚蠢的解决方案需要您事先做一些事情SELECT player_id FROM somewhere,这应该不成问题。

为了使单个查询高效,请确保您在两列上有一个索引,player_id并且event_date.

于 2013-03-15T08:28:19.573 回答