我有以下查询,它为每个查询获取id
最新的N :observations``station
SELECT id
FROM (
SELECT station_id, id, created_at,
row_number() OVER(PARTITION BY station_id
ORDER BY created_at DESC) AS rn
FROM (
SELECT station_id, id, created_at
FROM observations
) s
) s
WHERE rn <= #{n}
ORDER BY station_id, created_at DESC;
我有指标的id
,station_id
,created_at
。
这是我想出的唯一解决方案,每个站最多可以获取单个记录。但是,它非常慢(81000条记录的表为154.0毫秒)。
如何加快查询速度?
假设至少Postgres 9.3。
首先,多列索引将有助于:
CREATE INDEX observations_special_idx
ON observations(station_id, created_at DESC, id)
created_at DESC
的拟合度稍好一些,但如果不使用,索引仍将以几乎相同的速度向后扫描DESC
。
假设created_at
已定义NOT NULL
,否则DESC NULLS LAST
在索引 和 查询中考虑:
最后一列id
仅在从中获得仅索引的扫描时才有用,如果不断添加许多新行,则可能无法使用。在这种情况下,请id
从索引中删除。
简化查询,内部子选择无济于事:
SELECT id
FROM (
SELECT station_id, id, created_at
, row_number() OVER (PARTITION BY station_id
ORDER BY created_at DESC) AS rn
FROM observations
) s
WHERE rn <= #{n} -- your limit here
ORDER BY station_id, created_at DESC;
应该会快一点,但仍然很慢。
station_id
id定义为NOT NULL
。为了 真正 快,您需要等效的 宽松索引扫描 (尚未在Postgres中实现)。相关答案:
如果您有一个单独的表stations
(似乎是这样),则可以使用 JOIN LATERAL
(Postgres
9.3+)进行模拟:
SELECT o.id
FROM stations s
CROSS JOIN LATERAL (
SELECT o.id
FROM observations o
WHERE o.station_id = s.station_id -- lateral reference
ORDER BY o.created_at DESC
LIMIT #{n} -- your limit here
) o
ORDER BY s.station_id, o.created_at DESC;
如果您没有的表格stations
,那么下一个最好的办法就是创建并维护一个表格。可能添加外键引用以增强关系完整性。
如果那不是一个选择,则可以动态地提取这样的表。简单的选择是:
~~SELECT DISTINCT station_id FROM observations;
SELECT station_id FROM observations GROUP BY 1;~~
但是任何一个都需要顺序扫描并且很慢。使Postgres使用station_id
具有 递归CTE的 上述索引(或任何具有前导列的btree索引):
WITH RECURSIVE stations AS (
( -- extra pair of parentheses ...
SELECT station_id
FROM observations
ORDER BY station_id
LIMIT 1
) -- ... is required!
UNION ALL
SELECT (SELECT o.station_id
FROM observations o
WHERE o.station_id > s.station_id
ORDER BY o.station_id
LIMIT 1)
FROM stations s
WHERE s.station_id IS NOT NULL -- serves as break condition
)
SELECT station_id
FROM stations
WHERE station_id IS NOT NULL; -- remove dangling row with NULL
将其用作上述简单查询中的表的 替代品stations
:
WITH RECURSIVE stations AS (
(
SELECT station_id
FROM observations
ORDER BY station_id
LIMIT 1
)
UNION ALL
SELECT (SELECT o.station_id
FROM observations o
WHERE o.station_id > s.station_id
ORDER BY o.station_id
LIMIT 1)
FROM stations s
WHERE s.station_id IS NOT NULL
)
SELECT o.id
FROM stations s
CROSS JOIN LATERAL (
SELECT o.id, o.created_at
FROM observations o
WHERE o.station_id = s.station_id
ORDER BY o.created_at DESC
LIMIT #{n} -- your limit here
) o
WHERE s.station_id IS NOT NULL
ORDER BY s.station_id, o.created_at DESC;
这应该仍然比您 的数量级 要快。
对于我的具体情况,n=4,但可能有一天需要n=5或n=6。 我需要的顶级描述:我有一个表单,允许我将名称和日期添加到跳转日志中。我需要构建一个查询,该查询将显示每个跳转器的四个最近跳转,每个日期有一列。 我的表单将数据存储在“JUMP”表中,该表有3个字段:JUMPID、NAME、DATE。示例数据如下所示: 我现在使用的查询返回每个跳线最近的4次跳转,但将所有日期存储在同一列中。查询是: 此查询
问题内容: 我正在尝试并且未能将我相对简单的SQL语句转换为可在Doctrine中使用的语句。 这是SQL语句,当对我的数据库运行时,它可以按要求工作: 到目前为止,这是DQL尝试: 当前哪个出现此错误: 表格本身非常简单:ID,名称,分数,平台,日期 有多个名称相同但得分不同的条目。我只想显示每个名称的“高分”。我已经尝试了一两天了,没有运气。谁能指出我正确的方向? 问题答案: 您尝试使用主义进
问题内容: 我进行了很多搜索,但找不到有用的答案: 我想通过用户给我一个开始和结束日期来列出用户定义的时间段的总计。从开始日期到开始日期之间的每次总计应该相加,并在每一天添加1天。因此最后一行给出了从开始到结束日期的总计。示例:-给定期间=开始2013-01-01,结束= 2013-01-31 所以我有一个查询谁计算所有天: 我有一个查询谁每天计算总数 现在将这两者结合起来很难得到我的最终结果。
问题内容: 如何控制/限制提交给的任务?我已经发送了SMS消息,并且我需要控制执行程序,以便它最多只能以每秒N条消息的速度发送。 问题答案: 假设您为每个任务创建一条SMS消息,则可以使用ScheduleExecutorService。 将任务添加到队列中,它们将以每秒10个的速度处理。
问题内容: 我指的是以下查询,以找到雇员的Nth最高薪水。 一位先生说,此查询有效。有人可以解释一下如何将COUNT(n等于1到X,其中X是不同工资总额)的值等于&n会产生这个结果吗? 我试图了解数据库如何在内部处理此查询并产生结果? 谢谢你。 问题答案: 首先,查询将返回 最低 薪水值。要返回最高薪水值,您必须更改为。 接下来,此查询的工作方式是:首先找到一个唯一的薪水值列表作为一个派生表,然后
问题内容: 我想在名为 id的 列( 主键)中 从MySQL数据库中选择最后50行。目标是行应该被分类 ID 在 ASC 秩序,这就是为什么这个查询不工作 同样值得注意的是,可以对行进行操作(删除),这就是为什么以下查询也不起作用的原因 问题 :如何从MySQL数据库中检索可以操纵并按ASC顺序排列的最后N行? 问题答案: 您可以使用子查询来做到这一点: 这将从中选择 最后 50行,然后按升序对其