sql - Oracle 11g - 为什么 SELECT COUNT(*) 比 SELECT * 慢无限?

标签 sql oracle oracle11g

我在 Oracle 11g 中有一个这样的查询:

SELECT *
FROM CATAT, CG, CCSD
WHERE CATAT.ID = 1007642
AND CG.C_ID = CATAT.ID
AND CATAT.IS_PARENT = 1
AND CCSD.G_ID = CG.ID

在这种情况下,查询返回零行,并且几乎立即执行。但是,如果我将其更改为:
SELECT COUNT(*) AS ROW_COUNT
FROM CATAT, CG, CCSD
WHERE CATAT.ID = 1007642
AND CG.C_ID = CATAT.ID
AND CATAT.IS_PARENT = 1
AND CCSD.G_ID = CG.ID

它永远不会回来 - 我已经让查询运行了超过 5 分钟,但它仍然没有完成。事实上,除了 SELECT * 之外的任何东西都需要非常长的时间来运行。例如。 SELECT CG.ID FROM... , 或 SELECT CATAT.* FROM...
此查询唯一不寻常的是 CCSD 表中有数百万行数据。 CCSD.G_ID上有索引,所以不能缺少索引。

我只是不明白为什么查询会立即返回零行 SELECT *如果你做其他事情,应该花这么长时间吗?任何人都可以对此有所了解吗?

更新

这是SELECT * FROM...的解释计划询问:
explain plan 1

这是SELECT COUNT(*) FROM...的解释计划询问:
enter image description here

最佳答案

如果您改为运行此查询,会发生什么?

SELECT COUNT(*) AS ROW_COUNT
FROM CATAT
WHERE CATAT.ID = 1007642
AND CATAT.IS_PARENT = 1
AND EXISTS(SELECT 1 FROM CG WHERE CG.C_ID = CATAT.ID AND EXISTS(SELECT 1 FROM CCSD WHERE CCSD.G_ID = CG.ID))

我相信问题在于您在查询中的双重连接,

希望能帮助到你!

编辑:

详细说明一下,在您的原始查询中:
SELECT COUNT(*) AS ROW_COUNT
**FROM CATAT, CG, CCSD**
WHERE CATAT.ID = 1007642
AND CG.C_ID = CATAT.ID
AND CATAT.IS_PARENT = 1
AND CCSD.G_ID = CG.ID

第二行是问题所在,当您在 Oracle 的 from 子句中列出其他表时,这意味着您正在编写隐式连接 IF,并且仅当您列出每个表上的所有主键并将其与不同表上的另一列匹配时。根据您在 where 子句中添加的主键组件,它将导致常规内部连接(如果您匹配所有主键列),或者它可能导致类似于笛卡尔积的结果,我相信计划就是这种情况您在图片中发布,我可以在查询计划中看到带有选项笛卡尔的合并连接。

所有这些都意味着数据库正在生成一个非常大的表,并且该表中的行数是 CCSD 中的所有行 * CG 中的所有行 * CATAT 中的所有行(CCSD 有几百万,正如你所说,所以这个导致您感觉到的缓慢),然后尝试遍历此临时表以检查您拥有的过滤器。

发生此问题是因为原始查询未针对该任务进行优化,而我发布的查询是。

我所做的是阅读您查询以了解您要做什么,您正在尝试列出具有特定 ID 和 IS_PARENT = 1 的表 CATAT 的子集,但您只想列出那些 ID (CATAT.ID) 位于(或存在于)表 CG 和表 CCSD 中。在编写查询时,我尝试使用与条件中相同的级联,但我最初发布的查询也可以这样编写:
SELECT COUNT(*) AS ROW_COUNT
FROM CATAT
WHERE CATAT.ID = 1007642
AND CATAT.IS_PARENT = 1
AND EXISTS(SELECT 1 FROM CG WHERE CG.C_ID = CATAT.ID )
AND EXISTS(SELECT 1 FROM CCSD WHERE CCSD.G_ID = CATAT.ID)

现在此查询与您编写的原始查询完全相同,但没有连接。为了解决这个查询,数据库通过 ID 和 IS_PARENT 遍历表 CATAT 匹配(有一个索引使得这真的很快),一旦一行匹配前两个条件,数据库就会尝试通过 C_ID 在表 CG 上查找现有记录(再次真的如果您有索引,则很快),然后它会尝试按 ID 对表 CCSD 执行相同的操作。这最后 2 次搜索在我发布的第一个查询中是级联的,但想法是相同的:您的查询运行缓慢,因为正在创建笛卡尔积(可能已优化,但仍会产生大量行)而我write 只是按 ID 遍历表(没有合并),这些列中可能已经有索引,这就是它运行速度快的原因。

关于sql - Oracle 11g - 为什么 SELECT COUNT(*) 比 SELECT * 慢无限?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19641220/

相关文章:

sql - 外联盟等效项 - GBQ

oracle - 如何将 Oracle (C)LOB 导入另一个表空间

oracle - 检查约束可以与另一个表相关吗?甲骨文

oracle - 具有 Windows 身份验证的 cx_Oracle

sql - -bash : imp: command not found oracle

mysql - 多个 SQL 选择使用值来进一步搜索

sql - PL/SQL 中不带 + 号的增量日期/日

sql - 数据库仓库设计: fact tables and dimension tables

ROracle 未获取全文变量

database - 如何找到前 10 个昂贵的 sql -Oracle