Oracle 上 SELECT * 和 SELECT COUNT(*) 之间的结果大小不同

Posted

技术标签:

【中文标题】Oracle 上 SELECT * 和 SELECT COUNT(*) 之间的结果大小不同【英文标题】:Different result size between SELECT * and SELECT COUNT(*) on Oracle 【发布时间】:2016-09-12 10:38:19 【问题描述】:

我在 oracle 数据库上有一个奇怪的行为。我们插入了大约 310 万条记录。到目前为止一切都很好。

插入完成后不久(大约 1 到 10 分钟)我执行两条语句。

    从表中选择 COUNT(*) 从表中选择 *

第一个语句的结果很好,它给了我插入的确切行数。

第二个语句的结果现在是问题所在。根据时间的不同,返回的行数例如比第一个语句的结果低 500K 左右。两种结果的差异随着时间的推移而减小。

所以我必须等待 15 到 30 分钟,然后两个语句才能返回相同的行数。

我已经与 oracle dba 讨论过这个问题,但他不知道这是怎么发生的。

有什么想法、问题或建议吗?

更新

当我只选择一个索引列时,我得到了正确的行数。 当我改为选择非索引列时,我再次得到错误的行数。

【问题讨论】:

您是否在同一个会话中同时运行两个选择?你是如何插入行的?这是否可重现(也就是说,它每次您插入到表中都会发生?您怎么知道select * from TABLE 返回了多少行?您是在客户端还是 IDE 中滚动浏览它们?什么是select count(*) from (select * from TABLE)的行为吗? 否,两个 select 语句使用不同的会话。我如何插入是什么意思?我们使用普通的 INSERT 语句,如 INSERT INTO TABLE (COLUM1, COLUMN2...COLUMNX) VALUES (1, 2, ...X) 。是的,它可以被复制并且在其他插入过程中也会发生。我们的软件中有一个计数选项,可以简单地计算返回的所有行。我会测试你的陈述。 SELECT COUNT(*) FROM (SELECT * FROM TABLE) 语句的结果给了我正确的行数。 是的,但在同一时间窗口select * from TABLE 给您错误的行数? @APC 是的,这是正确的。我执行了 SELECT COUNT(*) FROM (SELECT * FROM TABLE) 这给了我正确的行数。在此之后,我只直接执行语句 SELECT * FROM TABLE 并且我得到了错误的行数。 【参考方案1】:

对我来说这听起来不像是一个错误,如果我理解正确的话,Oracle 获取整个表只是需要时间。毕竟,300万可不是小数目。

与计数相反,它会带来 1 条记录与总行数。

如果经过一段时间的等待,输出的记录数等于 count 查询返回的记录数,那么一切都很好。

【讨论】:

确实第一个语句只返回一行,而另一个语句必须返回所有 300 万行。但是无论如何,当两个语句都完成时,它们应该具有相同的结果。我的意思是从第一条语句返回的数字必须与第二条语句中的行数相同。事实并非如此。 您说 15 - 30 分钟后它工作正常。这意味着什么?您是否在同一会话中同时运行两者? 当我在等待大约 15 到 30 分钟后执行上述语句时,结果符合预期。这就是我的意思,15 - 30 分钟后一切正常。并且没有两个语句使用不同的会话。【参考方案2】:

您是否已经通过这些事情进行了验证:

1- 计算单列而不是 * ALL 来验证两个结果

2- 您可以通过添加 where 子句来验证两个查询结果,并通过删除条件逐渐选择更多行,这样您就可以解决两个返回不同值的问题。

【讨论】:

1 COUNT 个单列而不是 * 没有区别。 您是否也可以尝试通过使用某些条件从两个查询中选择部分计数。 2 这背后的想法是什么?我的意思是这怎么能帮助我理解发生了什么? 通过这种方式,我们可以找到在哪个深度的数据中给出不同的计数,或者仅在计算整个数据的情况下。 应该指出,对单个列的计数不会计算为 NULL 的行【参考方案3】:

我认为您应该检查执行计划以识别缺失的索引以提高性能。 添加缺失的索引并检查结果。

为什么缺少索引是无效的:

要计算行数,Oracle 引擎不需要去抛出分页操作。但是在从表中获取所有详细信息时,需要进行分页。

分页过程依赖于在表上创建的索引来有效和快速地获取数据。

因此,为了减少第二条语句的时间,您应该找到缺失的索引并创建这些索引。

如何查找缺失的索引:

您可以从 DBA_HIST_ACTIVE_SESS_HISTORY 开始,然后查看所有包含该类型提示的语句。

从那里,您可以从该提示中提取索引名称,然后在 dba_indexes 上进行查找以查看索引是否存在、是否有效等。

【讨论】:

我不太确定执行计划对我有什么帮助?我没有性能问题。另外,缺少索引怎么会对此负责? 更新了答案中的详细信息。 这是另一个问题的答案。

以上是关于Oracle 上 SELECT * 和 SELECT COUNT(*) 之间的结果大小不同的主要内容,如果未能解决你的问题,请参考以下文章

oracle学习篇六:子查询

选择语句在 Oracle 11 上给出 ora-03113

查询oracle用户角色权限

oracle知识点

oracle习题

mariad(selec的使用)