Oracle中的全文搜索优化

时间:2015-01-22 11:50:24

标签: php sql oracle doctrine-orm query-optimization

欢迎, 我有一个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!

1 个答案:

答案 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);