优化SQL查询

dov*_*mir 3 sql optimization oracle11g

我有一个怪物遗留查询,这是我的程序的核心,查询需要太多时间,什么是使其运行更快的最佳方法?我用的是oracle 11g

 SELECT   *
     FROM     ( SELECT  COUNT(*) AS countme,
                       string_value        ,
                       name                ,
                       property_id         ,
                       category_id
              FROM    ( SELECT DISTINCT a.string_value,
                                        a.name        ,
                                        a.property_id ,
                                        b.product_id  ,
                                        a.category_id
                       FROM             filter_criterias a
                                        JOIN product_properties b
                                        ON              (
                                                                          a.property_id = b.property_id
                                                         AND
                                                                          (
                                                                                           (
                                                                                                            isnumber(b.value)        IS NOT NULL
                                                                                           AND              isnumber(a.range_bottom) IS NOT NULL
                                                                                           AND              isnumber(a.range_top)    IS NOT NULL
                                                                                           AND
                                                                                                            (
                                                                                                                             a.range_bottom >a.range_top
                                                                                                            AND              b.value       >= a.range_bottom
                                                                                                            OR               a.range_bottom<=a.range_top
                                                                                                            AND              b.value       >= a.range_bottom
                                                                                                            AND              b.value       <=a.range_top
                                                                                                            )
                                                                                           )
                                                                          )
                                                         )
                                        JOIN PRODUCT_CATEGORY prc
                                        ON               (
                                                                          prc.sku         = b.product_id
                                                         AND              prc.category_id = a.category_id
                                                         )
                                        JOIN PRODUCT pr
                                        ON               (
                                                                          b.product_id = pr.SKU
                                                         AND              pr.visible   = '1'
                                                         )
                       )
              GROUP BY (string_value, name, property_id,category_id)

              UNION

              SELECT   COUNT(*) AS countme,
                       string_value       ,
                       name               ,
                       property_id        ,
                       category_id
              FROM    ( SELECT DISTINCT a.string_value,
                                        a.name        ,
                                        a.property_id ,
                                        b.product_id  ,
                                        a.category_id
                       FROM             filter_criterias a
                                        JOIN product_properties b
                                        ON              (
                                                                          a.property_id = b.property_id
                                                         AND
                                                                          (
                                                                                           (
                                                                                                            a.name= b.value
                                                                                           )
                                                                          )
                                                         )
                                        JOIN PRODUCT_CATEGORY prc
                                        ON               (
                                                                          prc.sku         = b.product_id
                                                         AND              prc.category_id = a.category_id
                                                         )
                                        JOIN PRODUCT pr
                                        ON               (
                                                                          b.product_id = pr.SKU
                                                         AND              pr.visible   = '1'
                                                         )
                       )
              GROUP BY (string_value, name, property_id,category_id)
              )
     ORDER BY 5,4,3,2
Run Code Online (Sandbox Code Playgroud)

这是解释计划

    "Optimizer" "Cost"  "Cardinality"   "Bytes" "Partition Start"   "Partition Stop"    "Partition Id"  "ACCESS PREDICATES" "FILTER PREDICATES"
"SELECT STATEMENT"  "ALL_ROWS"      "1298"  "2"         "542"   ""  ""  ""  ""  ""
"SORT(ORDER BY)"    ""              "1298"  "2"         "542"   ""  ""  ""  ""  ""
"VIEW"              ""              "1297"  "2"         "542"   ""  ""  ""  ""  ""
"SORT(UNIQUE)"      ""              "1297"  "2"         "74"    ""  ""  ""  ""  ""
"UNION-ALL" ""      ""              ""  ""  ""          ""  ""  ""  ""
"HASH(GROUP BY)"    ""              "661"   "1"         "37"    ""  ""  ""  ""  ""
"VIEW"              ""              "659"   "1"         "37"    ""  ""  ""  ""  ""
"HASH(UNIQUE)"      ""              "659"   "1"         "95"    ""  ""  ""  ""  ""
"NESTED LOOPS"      ""              ""  ""  ""          ""  ""  ""  ""  ""
"NESTED LOOPS"      ""              "658"   "1"         "95"    ""  ""  ""  ""  ""
"HASH JOIN"         ""              "493"   "1"         "81"    ""  ""  ""  ""B"."PRODUCT_ID"=TO_NUMBER("PRC"."SKU") AND "A"."CATEGORY_ID"=SYS_OP_C2C("PRC"."CATEGORY_ID")" ""
"HASH JOIN"         ""              "369"   "2"         "128"   ""  ""  ""  ""B"."PROPERTY_ID"=TO_NUMBER("A"."PROPERTY_ID")"    ""A"."RANGE_BOTTOM">"A"."RANGE_TOP" AND "A"."RANGE_BOTTOM"<=TO_NUMBER("B"."VALUE") OR "A"."RANGE_BOTTOM"<="A"."RANGE_TOP" AND "A"."RANGE_BOTTOM"<=TO_NUMBER("B"."VALUE") AND "A"."RANGE_TOP">=TO_NUMBER("B"."VALUE")"
"TABLE ACCESS(FULL) BNET.B_FILTER_CRITERIAS"    "ANALYZED"  "36"    "28"    "1148"  ""  ""  ""  ""  ""ISNUMBER"(TO_CHAR("A"."RANGE_BOTTOM")) IS NOT NULL AND "ISNUMBER"(TO_CHAR("A"."RANGE_TOP")) IS NOT NULL"
"TABLE ACCESS(FULL) BNET.B_PRODUCT_PROPERTIES"  "ANALYZED"  "332"   "12566" "289018"    ""  ""  ""  ""  ""ISNUMBER"("B"."VALUE") IS NOT NULL"
"TABLE ACCESS(FULL) BNET.WLCS_PRODUCT_CATEGORY" "ANALYZED"  "124"   "129762"    "2205954"   ""  ""  ""  ""  ""
"INDEX(RANGE SCAN) BNET.WLCS_PROD_VISIBLE_IDX"  "ANALYZED"  "12"    "6208"  ""  ""  ""  ""  ""PR"."VISIBLE"='1'"    ""
"TABLE ACCESS(BY INDEX ROWID) BNET.WLCS_PRODUCT"    "ANALYZED"  "164"   "1" "14"    ""  ""  ""  ""  ""B"."PRODUCT_ID"=TO_NUMBER("PR"."SKU")"
"HASH(GROUP BY)"    ""              "637"   "1"         "37"    ""  ""  ""  ""  ""
"VIEW"              ""              "635"   "1"         "37"    ""  ""  ""  ""  ""
"HASH(UNIQUE)"      ""              "635"   "1"         "91"    ""  ""  ""  ""  ""
"HASH JOIN"         ""              "634"   "1"         "91"    ""  ""  ""  ""B"."PRODUCT_ID"=TO_NUMBER("PRC"."SKU") AND "A"."CATEGORY_ID"=SYS_OP_C2C("PRC"."CATEGORY_ID")" ""
"NESTED LOOPS"      ""              ""      ""  ""  ""  ""  ""  ""  ""
"NESTED LOOPS"      ""              "509"   "1"         "74"    ""  ""  ""  ""  ""
"HASH JOIN"         ""              "345"   "1"         "60"    ""  ""  ""  ""B"."PROPERTY_ID"=TO_NUMBER("A"."PROPERTY_ID") AND "A"."NAME"="B"."VALUE"" ""
"TABLE ACCESS(FULL) BNET.B_FILTER_CRITERIAS"    "ANALYZED"  "35"    "11257" "416509"    ""  ""  ""  ""  ""
"TABLE ACCESS(FULL) BNET.B_PRODUCT_PROPERTIES"  "ANALYZED"  "309"   "251319"    "5780337"   ""  ""  ""  ""  ""
"INDEX(RANGE SCAN) BNET.WLCS_PROD_VISIBLE_IDX"  "ANALYZED"  "12"    "6208"  ""  ""  ""  ""  ""PR"."VISIBLE"='1'"    ""
"TABLE ACCESS(BY INDEX ROWID) BNET.WLCS_PRODUCT"    "ANALYZED"  "164"   "1" "14"    ""  ""  ""  ""  ""B"."PRODUCT_ID"=TO_NUMBER("PR"."SKU")"
"TABLE ACCESS(FULL) BNET.WLCS_PRODUCT_CATEGORY" "ANALYZED"  "124"   "129762"    "2205954"   ""  ""  ""  ""  ""
Run Code Online (Sandbox Code Playgroud)

Mat*_*lie 5

一个潜在的巨大问题来源是您必须使用ISNUMBER.

如果将数值存储为文本,然后使用诸如"x <= y"之类的操作,则会完成许多负面操作:
- 在使用字符串之前必须将字符串解析为数字
- 字符串的索引可能会承受与数字索引没有相似之处
- 如果索引无效,则会获得表扫描而不是索引搜索

我强烈建议将值存储为实数而不是字符串.不必使用ISNUMBER,不必转换每个值,因此实际上能够使用索引的组合可以具有极大的性能优势.

编辑

您刚刚添加的PLAN包含很多实例,TABLE ACCESS(FULL)其中一些实例与数值存储为字符串相关联.