【问题标题】:Primary key index is not being used未使用主键索引
【发布时间】:2019-03-21 22:01:53
【问题描述】:

我使用的是 Oracle 12C,我有以下代码

SELECT
        d.id,
        'Status' "ImportStatus",
        p.importid "ImportID",
        macid,
        p.daterequire "CreateDate",
        p.dateimport "DateImPort",
        TRANSLATE(p.accrequire USING NCHAR_CS) "CreateBy",
        TRANSLATE(p.accimport USING NCHAR_CS) "AccImPort",
        0 "isEdit",
        employee,
        deptid partner,
        equipmentid
    FROM
        (
            SELECT 
                id,
                importid,
                daterequire,
                dateimport,
                accrequire,
                accimport,
                subdeptid employee,
                deptid
            FROM
                tableA
            WHERE
                estatus = 2
                AND createdate BETWEEN to_timestamp('01/01/2019','dd/mm/yyyy') AND to_timestamp('12/02/2019','dd/mm/yyyy')
        ) p
        INNER JOIN tableB d ON d.importid = p.id

TableA 有 5m 个值,TableB 有 3m 个值。

Importid 是具有 varchar2 数据类型的唯一列。 ID 是带有数字数据类型的 PK。

这是执行计划:

https://i.stack.imgur.com/tR2Q9.png

可以看出,PK中没有索引,成本高。有什么办法可以帮我解决吗?

谢谢!

【问题讨论】:

    标签: oracle primary-key oracle12c query-performance


    【解决方案1】:

    首先,您应该考虑到索引并不总是一个好主意

    如果 Oracle 必须从表中读取 大部分 数据,它将使用 FULL TABLE SCAN,因为它比先读取索引块然后再读取数据块要快。涉及的 IO 操作太多。

    现在,回到你的问题。
    如果您愿意,可以通过提供提示来强制 Oracle 使用索引:

    /*+ INDEX(table_name index_name) */
    

    您可以将其添加到您的查询中并检查查询计划会发生什么以及新计划将花费多少:

    SELECT  /*+ INDEX(tableA index_name) */     --replace 'index_name' with the name of your index
            d.id,
            'Status' "ImportStatus",
            p.importid "ImportID",
            macid,
            p.daterequire "CreateDate",
            p.dateimport "DateImPort",
            TRANSLATE(p.accrequire USING NCHAR_CS) "CreateBy",
            TRANSLATE(p.accimport USING NCHAR_CS) "AccImPort",
            0 "isEdit",
            employee,
            deptid partner,
            equipmentid
        FROM
            (
                SELECT 
                    id,
                    importid,
                    daterequire,
                    dateimport,
                    accrequire,
                    accimport,
                    subdeptid employee,
                    deptid
                FROM
                    tableA
                WHERE
                    estatus = 2
                    AND createdate BETWEEN to_timestamp('01/01/2019','dd/mm/yyyy') AND to_timestamp('12/02/2019','dd/mm/yyyy')
            ) p
            INNER JOIN tableB d ON d.importid = p.id
    

    【讨论】:

    • 我尝试使用提示强制但没用。它使成本和运行时间高于不强制
    • 这只意味着,Oracle 选择了一个更好的执行计划来执行您的查询,它不会使用索引(正如我之前所说,索引并不总是一个好主意)。为了提高性能,您可以尝试按 createdate(可能还有 estatus)列对 TableA 进行分区,看看是否有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    相关资源
    最近更新 更多