- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
答案:它确实在 O(log n) 中执行,就像简单的二进制搜索
前言:这实际上应该是 错误报告(针对所有 SQL 数据库实现) ,因为我发现了极端情况(这很常见, 应该很快 ,但不是),我想确定一下。到目前为止,事实证明我是正确的,查询优化器不是最优的。
我对 SQL 完全陌生,但我知道数据结构和算法是如何工作的。我期待 查找所选单位/用户的最新记录/事件必须非常快,因为数据库正在使用 B-Tree(索引)并且该查询非常 类似于在排序数组中查找插入点 用于记录某些单位/用户 ID 和最大时间(或 id+1,time=0)。
SQL Fiddle Example
像这样创建表和索引:
create table t (
id int, at time, id2 int
);
create unique index i on t (id, at);
create unique index i2 on t (id2);
insert into t (id, at, id2) values
(1, '12:00', 1001200),
(1, '12:30', 1001230),
(2, '12:00', 2001200),
(2, '13:00', 2001300);
select * from t
where id=1
order by at desc
limit 1;
select * from t
where id2<2000000
order by id2 desc
limit 1
where
匹配的所有行。条件(获取多行),然后选择第一个(
limit 1
)
而不是直接搜索我想要的唯一一条记录 (到目前为止证明,这不是最佳的)。我整天都在搜索和询问,但找不到任何可以真正快速完成所需操作的查询。
id2 = id*10000+at
, 找到最高的
id2
小于某个值(
id2 <= 199999
与
id2 < 2000000
相同,并且有效 - 找到
1001230
这意味着
id=1, at="12:30"
)。
2000000
将返回插入点,它就在我想要的记录之后)我确信它可以用 B-Tree 完成,但为什么在 SQL 中不可能呢?如此有用的查询!
Limit (cost=0.15..3.73 rows=1 width=16)
-> Index Scan Backward using i on t (cost=0.15..32.31 rows=9 width=16)
Index Cond: (id = 1)
最佳答案
In any case, it should do direct index search, nothing else is faster.
explain (analyze, buffers)
运行说明你会看到:
Limit (cost=0.15..1.49 rows=1 width=16) (actual time=0.018..0.018 rows=1 loops=1)
Buffers: shared hit=2
-> Index Scan Backward using i on t (cost=0.15..12.19 rows=9 width=16) (actual time=0.015..0.015 rows=1 loops=1)
Index Cond: (id = 1)
Buffers: shared hit=2
Planning time: 0.184 ms
Execution time: 0.049 ms
postgresql.conf
的安装中生成的 - 这就是为什么成本估算低于您的示例的原因)
Buffers: shared hit=2
意味着 Postgres 恰好需要两次 I/O 操作(从缓存中提供服务)来获得结果——而且它的速度是最快的。
Index Cond: (id = 1)
中查找行.但是由于索引只包含 ID 并且查询想要
全部 数据库必须执行另一个 I/O 操作才能获取所有列。
select *
的原因之一。被认为是糟糕的编码风格——它给了规划者更少的选择来让它正确。
Index Only Scan Backwards
- 但只有 4 行,这不太可能发生。
The only difference is that max estimated cost for that "Index Scan Backward" was huge
Index Scan Backwards
节点 - 因为计划者看到
limit
子句并且知道它永远不会扫描整个索引 - 它会在第一行之后停止。
Index Scan Backwards
报告的成本如果节点需要完全执行,节点是理论总成本。
I know that searching for "highest smaller than" in sorted array (and B-tree) is simple and fast - O(log n) - just like finding exact value or insertion point. But when we did try to use SQL the result was useless, lasted too long.
It usually is around 100ms which is not that bad, but sometimes becomes a bottleneck
explain (analyze, timing, buffers)
.如果它受 I/O 限制,那么您可能会考虑使用更多更快的 (=SSD) 硬盘。非常使用高端SSD
where id=1
) 时,计划并没有真正改变:
Limit (cost=0.56..1.23 rows=1 width=20) (actual time=0.026..0.027 rows=1 loops=1)
Output: id, at, id2
Buffers: shared hit=5
-> Index Scan Backward using i1 on stuff.t (cost=0.56..1001.81 rows=1501 width=20) (actual time=0.024..0.024 rows=1 loops=1)
Output: id, at, id2
Index Cond: (t.id = 1)
Buffers: shared hit=5
Planning time: 0.158 ms
Execution time: 0.054 ms
Index Scan Backwards
的成本估算是
批号现在更高了,但运行时根本没有改变,
的成本外 节点还是一样的。所以不要取
LIMIT
所在的内部节点的成本。被用作计划是否“正确”的标准。
关于sql - 为什么 SELECT * WHERE id=1 ORDERBY at LIMIT 1 不像简单的二进制搜索那样在 O(log n) 中执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41172731/
出现在 python 2.7.8 中。 3.4.1 不会发生这种情况。 示例: >>> id(id) 140117478913736 >>> id(id) 140117478913736 >>> id
好吧,我对动态创建的控件的 ID 很困惑。 Public Class TestClass Inherits Panel Implements INamingContainer
我收到下面的错误,说有堆栈溢出。发生这种情况是因为带有 IN (id, id, id...id) 的 SQL 语句有大量参数。有没有什么办法解决这一问题?这是在我使用 Eclipse 的本地环境中发生
为什么 CPython(不知道其他 Python 实现)有以下行为? tuple1 = () tuple2 = ()
为什么 CPython(对其他 Python 实现一无所知)有以下行为? tuple1 = () tuple2 = ()
非常简单的问题:当我有一个持久对象时,它通常有一个名为 ID 的属性(对于抽象类)。 那么..命名约定是ID还是Id? 例如。 public int ID { get; set; } 或 public
知道为什么我会收到此错误,我已经尝试了所有命名约定(小写/大写) 我正在使用 Vaadin,这是我的代码片段: public class Usercontainer extends BeanI
为什么 CPython(不知道其他 Python 实现)有以下行为? tuple1 = () tuple2 = ()
我需要改变表的所有主键 UPDATE TODO SET id = id + 1 但我做不到(Demo 来自 Ahmad Al-Mutawa 的回答)描述了原因。主键不能这样改。 我也不能根据这是 sq
我正在尝试列出与用户相关的讨论列表。 想象一下,如果你愿意的话: posts -------------------------------------------------------------
我有一个表,其中包含一些具有自己的 ID 和共享 SKU key 的文章。我尝试使用左连接进行查询,并使用组结果获取从查询返回的所有 id。 我的数据结构是这样的: id - name -
在下表People中: id name 1 James 2 Yun 3 Ethan 如果我想找到最大 ID,我可以运行此查询 select max(id) id from People; 结果是
我正在产品页面上创建评论模块,其中显示垃圾评论选项,并显示 onclick 显示和隐藏弹出窗口。现在它在单个评论中工作正常但是当评论是两个时它同时打开两个因为类是相同的。现在这就是为什么我想要获取父
根据 REST 哲学,PUT操作应该(取自维基百科): PUT http://example.com/resources/142 Update the address member of the co
我想知道如何在使用 PHP 或 JavaScript 进行身份验证后从 Google Analytics 获取 Property Id、View Id 和 Account Id?因为我希望能够将它们存
我想使用所选按钮的 ID 进行删除。但我不知道如何从中获取/获取 id。我尝试了 this.id 但不起作用。 这是我创建按钮的地方: var deleteEmployer= document.cre
我有一个具有以下结构的表“表” ID LinkedWith 12 13 13 12 14 13 15 14 16
请不要在未阅读问题的情况下将问题标记为重复。我确实发布了一个类似的问题,但 STACKOVERFLOW 社区成员要求我单独重新发布修改后的问题,因为考虑到一个小而微妙的修改,解决方案要复杂得多。 假设
在 Android Studio 中,我创建了一个 Person.java 类。我使用Generate 创建了getter 和setter 以及构造函数。 这是我的 Person.java 类: pu
如何在 jQuery 中制作这样的东西: //这是显示的主体 ID //当我悬停 #hover-id 时,我希望 #principal-id 消失并更改 。但是当我将光标放在 #this-id 上时
我是一名优秀的程序员,十分优秀!