Oracles MAX函数的大O是什么?
Oracle函数的最大值是O(1)、O(log n)还是O(n)相对于表中的行数?如果列上有B树索引,则查找最大值是O(log(n)),因为答案将是索引的最后(或第一)行。值存储在高度为O(log(n))的B树的最深节点中 如果没有索引,则为O(n),因为必须读取所有行才能确定最大值Oracles MAX函数的大O是什么?,oracle,complexity-theory,max,Oracle,Complexity Theory,Max,Oracle函数的最大值是O(1)、O(log n)还是O(n)相对于表中的行数?如果列上有B树索引,则查找最大值是O(log(n)),因为答案将是索引的最后(或第一)行。值存储在高度为O(log(n))的B树的最深节点中 如果没有索引,则为O(n),因为必须读取所有行才能确定最大值 注:O(n)表示法忽略常数,但在现实世界中,这些常数不能忽略。从磁盘读取和从内存读取之间的差异是几个数量级。访问索引的第一个值可能主要在RAM中执行,而大型表的完整表扫描将主要需要从磁盘读取。实际上,如果不指定查
注:O(n)表示法忽略常数,但在现实世界中,这些常数不能忽略。从磁盘读取和从内存读取之间的差异是几个数量级。访问索引的第一个值可能主要在RAM中执行,而大型表的完整表扫描将主要需要从磁盘读取。实际上,如果不指定查询、表定义和查询计划,很难说 如果您的表在计算
MAX
的列上没有索引,Oracle将不得不进行完整的表扫描。这将是O(n),因为您必须扫描表中的每个块。通过查看查询计划可以看到这一点
我们将生成一个包含100000行的表,并使用CHAR(1000)
列确保这些行相当大
SQL> create table foo( col1 number, col2 char(1000) );
Table created.
SQL> insert into foo
2 select level, lpad('a',1000)
3 from dual
4 connect by level <= 100000;
100000 rows created.
如果在计算的MAX
列上创建索引,Oracle可以对该索引执行MIN/MAX扫描。如果这是优化器选择的计划,那么这就是一个O(logn)操作。当然,作为一个实际问题,这在功能上是一个O(1)运算,因为指数的高度实际上永远不会超过4或5——这里的常数项将占主导地位
SQL> create index idx_foo_col1
2 on foo( col1 );
Index created.
SQL> select max(col1)
2 from foo;
MAX(COL1)
----------
100000
Execution Plan
----------------------------------------------------------
Plan hash value: 817909383
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
| 2 | INDEX FULL SCAN (MIN/MAX)| IDX_FOO_COL1 | 1 | 13 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
83 consistent gets
1 physical reads
0 redo size
527 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
但是事情变得更难了。MIN
和MAX
分别具有相同的O(logn)行为。但是,如果在同一个查询中同时有MIN
和MAX
,那么您会突然返回到O(n)操作。Oracle(截至11.2)尚未实现抓取索引的第一个块和最后一个块的选项
SQL> ed
Wrote file afiedt.buf
1 select min(col1), max(col1)
2* from foo
SQL> /
MIN(COL1) MAX(COL1)
---------- ----------
1 100000
Execution Plan
----------------------------------------------------------
Plan hash value: 1342139204
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 4127 (1)| 00:00:50 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
| 2 | TABLE ACCESS FULL| FOO | 106K| 1350K| 4127 (1)| 00:00:50 |
---------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
14542 consistent gets
0 physical reads
0 redo size
601 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
当然,在Oracle的后续版本中,可能会实现这种优化,这将回到O(logn)操作。当然,您也可以重写查询,以获得一个不同的查询计划,该计划返回到O(logn)
您知道对Oracle文档的引用吗?声明,MAX是O(log n),但也没有引用。@塞文:实际上我在考虑它,访问索引的第一行是O(log(n))
time,因为这将位于B树中x层深的节点中,其中x是O(log(n))。但是,由于x是一个非常小的数字,这真的不重要。我必须如何阅读执行计划?在哪里可以找到复杂性?@ceving-执行计划向您展示了Oracle如何选择执行特定查询。当您看到类似于TABLE ACCESS FULL
的内容时,这意味着Oracle必须访问表中的每个块,因此这将是O(n)。当您看到索引完全扫描(最小/最大)
时,这意味着Oracle必须访问索引的第一个(或最后一个)块,因此这将是O(log n)。
SQL> ed
Wrote file afiedt.buf
1 select min(col1), max(col1)
2* from foo
SQL> /
MIN(COL1) MAX(COL1)
---------- ----------
1 100000
Execution Plan
----------------------------------------------------------
Plan hash value: 1342139204
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 4127 (1)| 00:00:50 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
| 2 | TABLE ACCESS FULL| FOO | 106K| 1350K| 4127 (1)| 00:00:50 |
---------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
14542 consistent gets
0 physical reads
0 redo size
601 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> ed
Wrote file afiedt.buf
1 select (select min(col1) from foo) min,
2 (select max(col1) from foo) max
3* from dual
SQL>
SQL> /
MIN MAX
---------- ----------
1 100000
Execution Plan
----------------------------------------------------------
Plan hash value: 3561244922
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 2 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
| 2 | INDEX FULL SCAN (MIN/MAX)| IDX_FOO_COL1 | 1 | 13 | 2 (0)| 00:00:01 |
| 3 | SORT AGGREGATE | | 1 | 13 | | |
| 4 | INDEX FULL SCAN (MIN/MAX)| IDX_FOO_COL1 | 1 | 13 | 2 (0)| 00:00:01 |
| 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
7 recursive calls
0 db block gets
166 consistent gets
0 physical reads
0 redo size
589 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed