use*_*653 6 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
Run Code Online (Sandbox Code Playgroud)
在这种情况下,查询返回零行,并且几乎立即执行.但是,如果我将其更改为:
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
Run Code Online (Sandbox Code Playgroud)
它永远不会回来 - 我已经让查询运行超过5分钟,但它仍然没有完成.事实上,除SELECT*之外的任何事情都需要很长时间才能运行.例如SELECT CG.ID FROM...,或SELECT CATAT.* FROM...
这个查询唯一不寻常的是CCSD表中有数百万行数据.有一个索引CCSD.G_ID,所以它不能缺少索引.
我只是不明白为什么SELECT *如果你做了除此之外的其他事情,那么使用a立即返回零行的查询应该花费这么长时间?任何人都可以对此有所了解吗?
以下是SELECT * FROM...查询的解释计划:

以下是SELECT COUNT(*) FROM...查询的解释计划:

如果您运行此查询会发生什么?
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))
Run Code Online (Sandbox Code Playgroud)
我相信问题出在你在查询中的双连接中,
希望能帮助到你!
编辑:
在原始查询中详细说明:
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
Run Code Online (Sandbox Code Playgroud)
第二行是问题,当您在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)
Run Code Online (Sandbox Code Playgroud)
现在,此查询与您编写的原始查询完全相同,但没有连接.为了解决这个问题,数据库遍历IDAT和IS_PARENT匹配的表CATAT(有一个索引使得它真的很快),一旦一行符合前两个条件,数据库试图通过表CG上的C_ID找到现有记录(再次真的如果你有一个索引,则快速),之后它会尝试通过ID对表CCSD执行相同的操作.在我发布的第一个查询中,最后2个搜索是级联的,但是这个想法是相同的:您的查询运行缓慢,因为创建了一个笛卡尔积(可能是优化的,但仍导致大量行)而我的write只是通过ID遍历表(没有合并),这可能已经在这些列中有索引,这就是它运行速度快的原因.