欢迎, 我有一个Oracle数据库的优化问题。我想搜索一些与前端用户在搜索框中键入的文本相匹配的对象。我在我的应用程序中使用PHP和Doctrine,Doctrine生成如下代码:
SELECT p0_."BD" AS BD --...
FROM "P" p0_
LEFT JOIN "G" g1_ ON p0_.GID = g1_.ID
LEFT JOIN "PD" p2_ ON p0_.PDID = p2_.ID
LEFT JOIN "PI" p3_ ON p2_.ID = p3_.PDID --ONE TO MANY, SO OPERATOR 'IN' REQUIRED
LEFT JOIN "IT" i4_ ON i4_.ID = p3_.ITID
LEFT JOIN "A" a5_ ON p0_.AID = a5_.ID
LEFT JOIN "P" p6_ ON p0_.MPID = p6_.ID
LEFT JOIN "RS" r7_ ON p0_.RSID = r7_.ID
WHERE (((
LOWER(p2_."FN") LIKE '%abc%'
OR LOWER(p2_."GN") LIKE '%abc%'
OR LOWER(a5_."SN") LIKE '%abc%'
OR LOWER(a5_."CN") LIKE '%abc%'
OR LOWER(a5_."CON") LIKE '%abc%'))
OR p2_."ID" IN
(SELECT p8_."ID"
FROM "PI" p9_
LEFT JOIN "PD" p8_
ON p9_.PDID = p8_.ID
WHERE LOWER(p9_."VALUE") LIKE '%abc%'
))
AND p6_."ID" = p0_."ID";
数据库相当大(约半个行),系统返回结果需要大约40秒。
"解释计划"在SQL Developer中显示系统使用带有FULL TABLE ACCESS的HASH JOIN。使用嵌套循环不会改变很多东西(即使使用INDEX)。
是否有可能以某种方式优化此过程?
修改
以下查询返回相同的结果,但速度要快得多(1.5s):
SELECT p0_."BD" AS BD --...
FROM "P" p0_
LEFT JOIN "G" g1_ ON p0_.GID = g1_.ID
LEFT JOIN "PD" p2_ ON p0_.PDID = p2_.ID
LEFT JOIN "PI" p3_ ON p2_.ID = p3_.PDID
LEFT JOIN "IT" i4_ ON i4_.ID = p3_.ITID
LEFT JOIN "A" a5_ ON p0_.AID = a5_.ID
LEFT JOIN "P" p6_ ON p0_.MPID = p6_.ID
LEFT JOIN "RS" r7_ ON p0_.RSID = r7_.ID
WHERE
p0_.id IN
(
SELECT p0_A.id FROM "P" p0_A JOIN "PD" p2_A ON (p0_A.PDID = p2_A.ID AND (LOWER(p2_."GN") LIKE '%abc%' OR LOWER(p2_."FN") LIKE '%abc%'))
UNION
SELECT p0_B.id FROM "P" p0_B LEFT JOIN "PD" p2_B ON p0_B.PDID = p2_B.ID JOIN "PI" p3_B ON (p2_B.ID = p3_B.PDID AND(LOWER(p3_B."VALUE") LIKE '%abc%'))
--UNION ANOTHER SELECTS
)
AND p6_."ID" = p0_."ID";
诀窍是在查询的ON部分添加附加条件并执行JOIN而不是LEFT JOIN。它必须是子查询,因为该技巧仅适用于一个表的字段。不幸的是,Doctrine不支持UNION clausule。甲骨文的优化机制是愚蠢的,还是我错过了什么?也许我可以以某种方式修改查询?
Greathings!
答案 0 :(得分:0)
没有能够测试代码,这可能是你想要的吗?
SELECT P0_."BD" AS BD --...
FROM "P" P0_
LEFT JOIN "G" g1_ ON p0_.GID = g1_.ID
LEFT JOIN "PD" P2_ ON P0_.PDID = P2_.ID
LEFT JOIN "PI" p3_ ON p2_.ID = p3_.PDID
LEFT JOIN "IT" I4_ ON I4_.ID = P3_.ITID
LEFT JOIN "A" a5_ ON p0_.AID = a5_.ID
LEFT JOIN "P" P6_ ON P0_.MPID = P6_.ID
LEFT JOIN "RS" r7_ ON p0_.RSID = r7_.ID
LEFT JOIN (SELECT P0_A.ID FROM "P" P0_A JOIN "PD" P2_A ON (P0_A.PDID = P2_A.ID AND (LOWER(P2_."GN") LIKE '%abc%' OR LOWER(P2_."FN") LIKE '%abc%'))) XX ON P0_.ID = XX.ID
LEFT JOIN (SELECT P0_B.ID FROM "P" P0_B LEFT JOIN "PD" P2_B ON P0_B.PDID = P2_B.ID JOIN "PI" P3_B ON (P2_B.ID = P3_B.PDID AND(LOWER(P3_B."VALUE") LIKE '%abc%'))) YY ON P0_.ID = YY.ID
WHERE P6_."ID" = P0_."ID"
and (XX.ID is not null or XX.ID is not null);