我有以下sql需要很长时间才能执行,有没有更好的方法来编写它来提高速度。
任何帮助都非常值得赞赏。
由于
SELECT a.KeyField
FROM Details a,
Master b
WHERE a.ForeignKeyField = b.ForeignKeyField
AND a.KeyField IS NOT NULL
AND Date BETWEEN
TO_DATE ('01-01-2011', 'dd-mm-yyyy') AND TO_DATE ('31-12-2011', 'dd-mm-yyyy')
AND a.KeyField IN
(SELECT p.KeyField
FROM Details p,
Master q
WHERE q.ForeignKeyField = p.ForeignKeyField
AND p.KeyField IS NOT NULL
AND p.KeyField = a.KeyField
AND q.FKField2 = b.FKField2
GROUP BY p.KeyField,
q.Date HAVING COUNT (DISTINCT q.ForeignKeyField) > 1)
GROUP BY b.Id,
b.Name,
b.ForeignKeyField,
b.Date,
a.ForeignKeyField,
a.SomeOtherField,
a.KeyField,
b.EtcEtc
答案 0 :(得分:1)
在您的查询上运行EXPLAIN
,您将看到缓慢来自哪里。但是,一般情况下,如果您可以避免嵌套查询(IN
语句)和DISTINCT
,那么您的查询效果会更好。看看您是否可以在同一查询中两次加入Details
和Master
表并相应地放置索引
答案 1 :(得分:1)
首先,您需要学习正确的连接语法。我的猜测是,由于相关的子查询,Oracle正在选择次优的查询路径。我们将其更改为联接:
SELECT a.KeyField
FROM Details a join
Master b
on a.ForeignKeyField = b.ForeignKeyField join
(SELECT p.KeyField, q.Date, q.FKField2
FROM Details p join
Master q
on q.ForeignKeyField = p.ForeignKeyField
WHERE p.KeyField IS NOT NULL AND
q.FKField2 = b.FKField2
GROUP BY p.KeyField, q.Date
HAVING COUNT (DISTINCT q.ForeignKeyField) > 1
) t
on a.KeyField = t.KeyField and
b.FKField2 = t.FKField2
WHERE a.KeyField IS NOT NULL AND
Date BETWEEN TO_DATE ('01-01-2011', 'dd-mm-yyyy') AND TO_DATE ('31-12-2011', 'dd-mm-yyyy') AND
GROUP BY b.Id, b.Name, b.ForeignKeyField, b.Date, a.ForeignKeyField, a.SomeOtherField, a.KeyField,
b.EtcEtc
以这种方式编写也让我意识到Date上没有条件,尽管在子查询中使用了它。这是对的吗?
答案 2 :(得分:0)
确保您已准备好相关指数。检查执行计划以验证它们实际上是否正在使用。在选择索引时,Oracle非常挑剔。
答案 3 :(得分:0)
我不了解内部查询的原因。我会这样简化:
SELECT a.KeyField
FROM Details a,
Master b
WHERE a.ForeignKeyField = b.ForeignKeyField
AND a.KeyField IS NOT NULL
AND Date >= TO_DATE ('01-01-2011', 'dd-mm-yyyy')
AND Date <= TO_DATE ('31-12-2011', 'dd-mm-yyyy')
GROUP BY b.Id,
b.Name,
b.ForeignKeyField,
b.Date,
a.ForeignKeyField,
a.SomeOtherField,
a.KeyField,
b.EtcEtc
HAVING COUNT (DISTINCT q.ForeignKeyField) > 1
同时将BETWEEN
替换为>=, <=
将有助于