如何优化以下Oracle SQL视图?

9udxz4iz  于 2023-10-16  发布在  Oracle
关注(0)|答案(1)|浏览(115)

我们将实现一个Oracle SQL视图表,目前,它使用excessive count(*)来连接另一个表:

SELECT
        portfolio.id as id, 
        portfolio.name as name, 
        portfolio.number as number, 
        currency.id as currencyId,
        currency.key as currencyIso, 
        customer.id as cbsId,
        (CASE WHEN position_tbl.max_available_balance >0 THEN 'true' ELSE 'false' END) as hasAvailableBalance,
        (CASE WHEN wallet_tbl.wallet_count > 0 THEN 'true' ELSE 'false' END) as hasWallet, 
        (CASE WHEN account_tbl.fiat_account_count > 0 THEN 'true' ELSE 'false' END) as hasFiatAccount,
        wallet_tbl.wallet_count,
        account_tbl.fiat_account_count
    FROM SCHEMA.CUSTOMER customer
    INNER JOIN SCHEMA.PORTFOLIO portfolio on portfolio.customer_id = customer.id
    LEFT JOIN (
        SELECT COUNT(*) as wallet_count, 
            portfolio_number 
        FROM SCHEMA.WALLET 
        GROUP BY portfolio_number) wallet_tbl on wallet_tbl.portfolio_number= portfolio.portfolio_number
    LEFT JOIN (
        SELECT MAX(position.available_balance) as max_available_balance, 
            portfolio_number 
        FROM SCHEMA.POSITION position
        GROUP BY position.portfolio_number) position_tbl on position_tbl.portfolio_number =portfolio.portfolio_number
    INNER JOIN CURRENCY currency on currency.id = portfolio.reference_currency_id
    LEFT JOIN (
        SELECT COUNT(*) as fiat_account_count, 
            portfolio_id 
        FROM ACCOUNT 
        GROUP BY portfolio_id) account_tbl on account_tbl.portfolio_id = portfolio.id

有人能建议或建议什么可以优化这里的性能?

smdncfj3

smdncfj31#

  • 如果 * 这是一个独立的查询,或者如果它是作为一个视图查询的 *,而没有添加任何额外的 predicate *(这意味着没有理由这是一个“视图”),那么它可能会合并内联视图,并推迟GROUP BY直到连接之后,这会导致临时的多对多连接。也可能是不好的统计数据不恰当地驱动了嵌套循环。

如果是这种情况,那么,1)* 收集所有相关表的统计数据 。如果这还不能解决问题, 试试这些提示 *(在四个地方),看看效果如何:

SELECT /*+ USE_HASH(customer portfolio wallet_tbl currency account_tbl currency) PARALLEL(16) */
        portfolio.id as id, 
        portfolio.name as name, 
        portfolio.number as number, 
        currency.id as currencyId,
        currency.key as currencyIso, 
        customer.id as cbsId,
        (CASE WHEN position_tbl.max_available_balance >0 THEN 'true' ELSE 'false' END) as hasAvailableBalance,
        (CASE WHEN wallet_tbl.wallet_count > 0 THEN 'true' ELSE 'false' END) as hasWallet, 
        (CASE WHEN account_tbl.fiat_account_count > 0 THEN 'true' ELSE 'false' END) as hasFiatAccount,
        wallet_tbl.wallet_count,
        account_tbl.fiat_account_count
    FROM SCHEMA.CUSTOMER customer
    INNER JOIN SCHEMA.PORTFOLIO portfolio on portfolio.customer_id = customer.id
    LEFT JOIN (
        SELECT /*+ NO_MERGE */ COUNT(*) as wallet_count, 
            portfolio_number 
        FROM SCHEMA.WALLET 
        GROUP BY portfolio_number) wallet_tbl on wallet_tbl.portfolio_number= portfolio.portfolio_number
    LEFT JOIN (
        SELECT /*+ NO_MERGE */ MAX(position.available_balance) as max_available_balance, 
            portfolio_number 
        FROM SCHEMA.POSITION position
        GROUP BY position.portfolio_number) position_tbl on position_tbl.portfolio_number =portfolio.portfolio_number
    INNER JOIN CURRENCY currency on currency.id = portfolio.reference_currency_id
    LEFT JOIN (
        SELECT /*+ NO_MERGE */ COUNT(*) as fiat_account_count, 
            portfolio_id 
        FROM ACCOUNT 
        GROUP BY portfolio_id) account_tbl on account_tbl.portfolio_id = portfolio.id
  • 如果 *,但是,这是一个真实的视图,您正在使用其他 predicate 进行查询,那么上面的内容可能不适用,并且您还没有给我们您试图调优的实际SQL。当你查询一个视图时,数据库执行的程序不仅包括视图内容,还包括调用视图的SQL,这可以改变一切。例如,如果你将上面的代码编译成一个视图,然后用它来查询一个特定的客户或投资组合,那么我上面建议的提示将是绝对错误的,因为这会将你要查找的数据从这些表的100%变成一小部分,这会改变最佳执行计划。如果这是正在发生的事情,您必须确保对所有连接列和 predicate 列进行正确的索引,并维护当前的统计信息,因为提示各种不同查询使用的视图很少成功,因为这些调用查询如何更改需要发生的事情。出于这个原因,我通常建议开发人员尽量减少对视图的使用。

相关问题