如何在查询提示中为单个表的不同连接选择不同的提示?

Posted

技术标签:

【中文标题】如何在查询提示中为单个表的不同连接选择不同的提示?【英文标题】:How can I choose different hints for different joins for a single table in a query hint? 【发布时间】:2010-03-26 15:08:06 【问题描述】:

假设我有以下查询:

select * from A, B, C, D
where A.x = B.x
and B.y = C.y
and A.z = D.z

我在 A.x 和 B.x 和 B.y 和 C.y 和 D.z 上有索引

A.z. 上没有索引

我怎样才能给这个查询一个提示,在 A.x 上使用 INDEX 提示,但在 A.z 上使用 USE_HASH 提示?似乎提示只采用表名,而不是特定的连接,因此当使用具有多个连接的单个表时,我只能为所有连接指定一个策略。

替代方案,假设我在上述查询中使用了 LEADING 或 ORDERED 提示。这两个提示也只需要一个表名,那么我怎样才能确保 A.x = B.x 连接发生在 A.z = D.z 之前呢?我意识到在这种情况下我可以先列出 D,但想象 D 随后连接到 E,并且 D-E 连接是我在整个查询中想要的最后一个。

第三种配置——假设我希望 A.x 连接成为整个查询的第一个,并且我希望 A.z 连接成为最后一个。如何使用提示从 A 进行一次连接,然后是 B-C 连接,最后是 A-D 连接?

【问题讨论】:

否 - ORDERED 不采用表名。它告诉优化器在 FROM 子句中使用表的顺序。此外,在 Oracle 10g + 中,LEADING 提示接受任意数量的表 - 例如/*+LEADING(A B C D)*/ 【参考方案1】:

首先,使用此类提示应该是最后的手段,而不是编写查询的正常方式。大多数情况下,您应该确保优化器统计数据是最新的,并让 CBO 为自己制定最佳路径 - 这就是它的工作!

INDEX 提示可以像这样指定要使用的索引的名称:

SELECT /*+ INDEX (A, A_X_IDX) */ *
...

(假设 A.X 上的索引称为 A_X_IDX)。

您不能告诉 Oracle 在同一语句中使用 A.X 上的索引对表 A 使用哈希联接,这是没有意义的。但是,您可以(如果必须)为每个表指定访问路径,例如:

SELECT /*+ INDEX (A, A_X_IDX) INDEX(B, B_Y_IDX) USE_HASH(C) */ *

但重申一下,应该很少需要这样做。甲骨文已经投入了数百万美元和工时来开发 CBO,那么为什么要有效地关闭它呢?

【讨论】:

我对默认优化的行为非常满意,但是对于这个特定的查询(跨越数据库链接并使用多个视图),当我运行解释时,它显示的估计成本约为 700没有任何提示的计划。当我在没有提示的情况下运行查询时,大约需要 30 秒才能返回。当我指定一个 LEADING 提示时,它会显示 ~950 的成本,但会在 ~3.5 秒内返回。必须达到这种特异性水平非常令人沮丧,但我没有看到任何其他选择。 数据库链接可能会对性能造成很大影响。 DRIVING_SITE 提示在这里很有用 - 请参阅 download.oracle.com/docs/cd/B28359_01/server.111/b28310/…【参考方案2】:

在 SQL Server 上,您可以像这样执行哈希联合提示

SELECT * FROM table1 t1
INNER hash join table2 t2 ON  t1.id = t2.id

您还可以提供索引提示

select * from table1 t1
inner  join table2 t2 with (index( bla))  on  t1.id = t2.id

不知道 Oracle 中的语法是什么样的,顺便说一句,您为什么使用旧式联接?你还在用 8i 吗?

【讨论】:

我们使用的是 10g。我发现“旧”样式连接比新语法更具可读性。我已经对 ANSI 连接语法进行了几次尝试,但我觉得我并没有获得多少收获。我也有点不确定如何处理在 ON 子句中指定非连接条件,与所有连接都在一个块中时相比,我花了更多的时间从一个地方跳到另一个地方。 作为不久前硬着头皮切换到ANSI join语法的人,一开始我也没有明白这一点。看起来很尴尬。现在我是一个大粉丝。首先,如果您必须使用不同的 DBMS(例如 SQL Server),您将不会遇到语法问题。一旦你改变你的想法,它实际上更直观。你没有人问你“+”号是什么意思。它更具可读性。不知道“一个块中的所有连接”是什么意思,您当然可以在一个选择中拥有多个连接。尽管最初遇到阻力,但我很高兴我做出了改变。

以上是关于如何在查询提示中为单个表的不同连接选择不同的提示?的主要内容,如果未能解决你的问题,请参考以下文章

在单个查询中为每个 DISTINCT 选择几条记录

如何在单个 Scrapy 项目中为不同的蜘蛛使用不同的管道

是否可以在 jquery 函数中为 JQuery UI 工具提示设置不同的 UI 主题

如何在没有临时表的 SQL 查询中为组添加序列号

如何在spring security中为来自两个不同表的不同用户配置身份验证?

PostgreSQL——代价估计