【问题标题】:What's happening behind the scenes when I query through SQL Developer?当我通过 SQL Developer 查询时,幕后发生了什么?
【发布时间】:2016-10-24 09:35:35
【问题描述】:

当我通过 SQL Developer 查询我的数据库时,我一直想知道幕后发生了什么。

与表的大小无关,默认情况下我总是最多得到 50 行。我可以在结果表上向下滚动,显然它会以某种方式延迟加载其余的结果。

显示前 50 个结果似乎不会随表的大小而变化(至少对于简单的 SELECT * FROM t),所以这让我相信 SQL Developer 包含了我的 SELECT 语句 s带有SELECT * FROM s WHERE rownum <= 50。如果是这种情况,正如我想象的那样,它不会显示在Explain Plan 选项卡上。

如果需要,SQL Developer 之后如何懒惰地得到其余的结果?它是否使用某种偏移量?它是否总是需要重做查询,而不是只取rownum <= 50 的行,而是为rownum <= 100, 150 等做它?那肯定是低效的。但除非它这样做,否则它可能会获取错误的行集(因为行的表配置可能在中间发生了变化!)。

我还假设默认情况下 SQL Developer 实际上只从服务器获取最少量的数据,也就是说,它实际上并没有获取所有内容,尽管只显示了一些结果。是这样吗?

有人能解释一下这个问题吗?

【问题讨论】:

  • 为什么不只为查询启用日志记录并检查日志?
  • 我以前查看过日志,但它们似乎只包括我自己编写的查询,而不是发送到服务器的内容。我们指的是同一种日志吗?

标签: oracle-sqldeveloper


【解决方案1】:

所以这让我相信 SQL Developer 用 SELECT * FROM s WHERE rownum 封闭了我的 SELECT 语句

不,这不是它的工作方式,原始查询中没有添加谓词来限制行数。

任何客户端的底层数据库驱动程序,无论是 JDBC 还是 ODP,都以块的形式从打开的游标中获取数据。在 SQL Developer 中,SQL array fetch Size (Tools\Preferences\Database\Advanced) 负责设置每次往返数据库服务器时应从游标获取多少行的值。因此,例如,如果您有一个包含 100 行的表,并且 array fetch size 设置为 50,您将在 2 次往返数据库 + 1 次额外行程中从该表中获取所有行。

但这并不意味着您只会看到 50 行。然而,将获取以 50 行为一组填充 SQL Developer 网格所需的许多行。因此,您可以在按下f9 or Ctrl+Enter 后看到显示的 100 行,并且需要两次 +1 往返到服务器。

【讨论】:

  • 这意味着数据库将保持与此查询相关联的状态?什么时候会丢弃?一旦我尝试运行下一个查询?还是由 SQL Developer 通知数据库何时可以发布此查询结果?
  • @devouredelysium 当您提交查询时,您会打开一个游标,该游标在执行时会生成可以获取的结果集(行集)。结果集中的行被编号。当您提交新查询时,将打开新游标并生成新结果集。每个会话的打开游标数受open_cursors 初始化参数的限制。
【解决方案2】:

正如其他人在这里提出的那样,跟踪数据库查询的简单步骤。

在 SQL Developer 中运行

 ALTER SESSION SET tracefile_identifier = mytest;
 alter session set events '10046 trace name context forever, level 1';

第一条语句帮助查找数据库服务器上的跟踪文件,第二条语句激活跟踪。

更多详情见docs

比运行示例查询,例如

 select owner, object_name from dba_objects

并向下滚动几页,例如到第 130 行。 关闭连接并检查跟踪文件:

 =====================
 PARSING IN CURSOR #210335064 len=42 dep=0 uid=48 oct=3 lid=48 tim=20962225002 hv=3579237936 ad='b7ef8180' sqlid='114vazvapdpjh'
 select owner, object_name from dba_objects
 END OF STMT
 PARSE #210335064:c=15600,e=31487,p=0,cr=4,cu=0,mis=1,r=0,dep=0,og=1,plh=2354722397,tim=20962225000
 EXEC #210335064:c=0,e=46,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2354722397,tim=20962225198
 FETCH #210335064:c=0,e=1650,p=0,cr=39,cu=0,mis=0,r=50,dep=0,og=1,plh=2354722397,tim=20962226907

 *** 2016-10-24 17:36:49.734

您会看到游标被解析、执行并提取了 50 行 (r=50)。 记下光标编号(#210335064)并在跟踪文件中进一步查看:

 FETCH #210335064:c=0,e=515,p=0,cr=16,cu=0,mis=0,r=50,dep=0,og=1,plh=2354722397,tim=20970608847

 *** 2016-10-24 17:37:03.376

提取了接下来的 50 行 ...

 FETCH #210335064:c=0,e=304,p=0,cr=6,cu=0,mis=0,r=50,dep=0,og=1,plh=2354722397,tim=20976035474

 *** 2016-10-24 17:37:19.866

获取接下来的 50 行,最后关闭游标

 CLOSE #210335064:c=0,e=300,dep=0,type=0,tim=20992663336

您已滚动超过 130 行,客户端执行了 3 次提取,默认提取大小为 50 行 您可以将提取大小设置为最大 200 - 在这种情况下,只有一次提取就足够了。

【讨论】:

  • 还有一个问题,我知道这可能高度依赖于数据库。如果我执行 SELECT * FROM x ORDER BY k,并且 k 没有被索引,那么服务器是否真的会急切地订购所有东西,还是会尝试分批 50 行?
  • 这里没有 RDBMS 依赖 - 是 SQL。如果你说给我来自x 的数据,按k 排序,你必须阅读整个表并对其进行排序——最小的键可能在最后一条记录中。
  • 您不需要对整个表格进行排序。您只能先对前 50 个元素进行排序,然后再对第 51-100 个元素进行排序,等等,而无需简单地使用二进制堆进行完整排序。这将具有不需要将完整查询结果保存在内存或磁盘中的优点,并且可能会更快地返回,如果在典型用例中用户只想查看前 50 行,则特别有用。回顾一下,虽然您肯定需要阅读整个表格,但实际上并不需要对整个表格进行排序。
猜你喜欢
  • 2023-03-14
  • 1970-01-01
  • 2010-11-22
  • 2010-10-27
  • 2011-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-23
相关资源
最近更新 更多