为什么查询提示 FIRST_ROWS(1000) 会导致性能下降?

str*_*cer 6 performance oracle

我有一个查询,其中包含用户提供的参数,可以根据用户的输入生成非常多的行。

如果用户提供非常非选择性的参数,则查询需要大量时间才能完成。如果查询将返回超过 1000 行,则应向用户提供错误消息。

该查询没有 order by 子句,只是连接了三个(大)表。

现在的想法是使用查询提示 FIRST_ROWS(1000) 来加速。SQL 开发人员中的测试表明成本指标显着降低(因子 10)。

查询是通过 Entitymanager 使用本机查询执行的。

但是,应用程序中的行为如下:持续时间OraclePreparedStatement.executeQuery减少了 60%。但是,现在花费了更多的时间EJBQueryImpl.getResultList,与省略查询提示相比,之前花费的时间不到 100 毫秒,从而导致性能下降。

代码本质上是:

Query query = em.createNativeQuery(sqlQuery); // sqlQuery has query hint "FIRST_ROWS(" + (maxResults + 1) + ")"

query.setMaxResults(maxResults + 1);

List<Object[]> resultList = query.getResultList();

if (maxResults != 0 && resultList.size() > maxResults) {
    resultSetTruncated = true;
}
Run Code Online (Sandbox Code Playgroud)

查询是:

SELECT ... FROM
    T1 
LEFT OUTER JOIN T2 on T1.pk1 = T2.pk1
        AND T1.pk2 = T2.pk2 
        AND T1.colx = T2.pk3
LEFT OUTER JOIN
    T3 
        ON T2.pk1 = T3.pk1
        AND T2.coly = T3.pk1
WHERE
    T1.pk1 IN ('081111') 
    AND EXISTS (
        SELECT 1 FROM T4 WHERE
            T1.PK1 = T4.PK1
            AND T2.PL2 = T4.PK2 
            AND T4.KIND = 'N' 
            AND T4.NORMALIZED LIKE 'DA%'
    )
Run Code Online (Sandbox Code Playgroud)

表 T3 非常大,感兴趣的情况下的指定条件不是很有选择性。

小智 1

您使用哪个版本的 Oracle 数据库?您本质上希望根据争论的内容制定不同的计划。Oracle 试图在 9i、10g 中实现这一点,并最终在 11g 中实现这一点。

使用 SQL 计划稳定性和自适应游标共享。

自适应游标共享会让数据库在检测到某个参数导致性能不佳时搜索更好的计划,这样下次就会表现得更好。SQL 计划稳定性确保数据库最终得到一组良好/可接受的计划,从而提供令人满意的性能。