3

我在 Django 中对远程 Oracle 服务器运行原始 SQL 查询。查询很长,需要一分半钟才能完成,但如果我使用 Oracle SQL Server 程序执行相同的查询,查询运行时间不到一秒。

为什么性能差别这么大?如何在 Django 中加快查询速度?

顺便说一句,我正在使用 Django 的开发服务器和配置文件工具栏(Django 1.5)。

更新:这是 Django 中的查询

holidays_filter = ''
if filters['holidays'] == 'exclude':
    holidays_filter = 'AND FECHAS.FESTIVO = 0'

hp_inner_join = ''
if filters['hour-mode'] == 'hp-sector-ps':
    hp_inner_join = """
        INNER JOIN
        EGW.RHP_CELLSEC_PS HPCELLPS
        ON UCELL2.DIA = HPCELLPS.DIA
           AND UCELL2.HORA = HPCELLPS.HORA
           AND UCELL2.RNC = HPCELLPS.RNC
           AND UCELL2.UTRANCELL = HPCELLPS.CELLID
        """
elif filters['hour-mode'] == 'hp-rnc-ps':    
    hp_inner_join = """
        INNER JOIN
        EGW.RHP_RNC_PS HPRNCPS
        ON UCELL2.DIA = HPRNCPS.DIA
           AND UCELL2.HORA = HPRNCPS.HORA
           AND UCELL2.RNC = HPRNCPS.RNC
        """

sql = """
  SELECT CUSTOM.DIA, CUSTOM.HORA,
         ROUND(CUSTOM.TRAF_CS57 + CUSTOM.TRAF_CS64 + CUSTOM.TRAF_CS12 + CUSTOM.TRAF_CSAMR12200 + CUSTOM.TRAF_CSAMR7950 + CUSTOM.TRAF_CSAMR5900 + CUSTOM.TRAF_CSAMR4750, 1) AS TRAFICO_CS_ERL,
         ROUND(CUSTOM.A + CUSTOM.B + CUSTOM.C + CUSTOM.D, 1) AS TRAFICO_PS_ERL

    FROM (SELECT TOTAL.DIA, TOTAL.HORA, TOTAL.RNC, TOTAL.UTRANCELL,
                 CASE
                     WHEN TOTAL.PMSAMPLESCS12RABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMCS12RABESTABLISH / TOTAL.PMSAMPLESCS12RABESTABLISH
                 END AS TRAF_CS12,
                 CASE
                     WHEN TOTAL.PMSAMPLESBESTCS57RABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTCS57RABESTABLISH / TOTAL.PMSAMPLESBESTCS57RABESTABLISH
                 END AS TRAF_CS57,
                 CASE
                     WHEN TOTAL.PMSAMPLESBESTCS64RABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTCS64RABESTABLISH / TOTAL.PMSAMPLESBESTCS64RABESTABLISH
                 END AS TRAF_CS64,
                 CASE
                     WHEN TOTAL.PMSAMPLBESTAMR12200RABESTABLIS = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTAMR12200RABESTABLISH / TOTAL.PMSAMPLBESTAMR12200RABESTABLIS
                 END AS TRAF_CSAMR12200,
                 CASE
                     WHEN TOTAL.PMSAMPLBESTAMR7950RABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTAMR7950RABESTABLISH / TOTAL.PMSAMPLBESTAMR7950RABESTABLISH
                 END AS TRAF_CSAMR7950,
                 CASE
                     WHEN TOTAL.PMSAMPLBESTAMR5900RABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTAMR5900RABESTABLISH / TOTAL.PMSAMPLBESTAMR5900RABESTABLISH
                 END AS TRAF_CSAMR5900,
                 CASE
                     WHEN TOTAL.PMSAMPLBESTAMR4750RABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTAMR4750RABESTABLISH / TOTAL.PMSAMPLBESTAMR4750RABESTABLISH
                 END AS TRAF_CSAMR4750,

                 CASE
                     WHEN TOTAL.PMSAMPLEBESTDCHPSINTRABESTABLI = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTDCHPSINTRABESTABLISH / TOTAL.PMSAMPLEBESTDCHPSINTRABESTABLI
                 END AS A,
                 CASE
                     WHEN TOTAL.PMSAMPLEFACHPSINTRABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMFACHPSINTRABESTABLISH / TOTAL.PMSAMPLEFACHPSINTRABESTABLISH
                 END AS B,
                 CASE
                     WHEN TOTAL.PMSAMPBESTPSHSADCHRABESTABLISH = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTPSHSADCHRABESTABLISH / TOTAL.PMSAMPBESTPSHSADCHRABESTABLISH
                 END AS C,
                 CASE
                     WHEN TOTAL.PMSAMPLBESTPSEULRABESTABLI = 0
                     THEN 0
                     ELSE TOTAL.PMSUMBESTPSEULRABESTABLISH / TOTAL.PMSAMPLBESTPSEULRABESTABLI
                 END AS D

            FROM (SELECT UCELL2.DIA, UCELL2.HORA, UCELL2.RNC, UCELL2.UTRANCELL,
                         SUM(UCELL2.PMSAMPLESCS12RABESTABLISH) AS PMSAMPLESCS12RABESTABLISH,
                         SUM(UCELL2.PMSUMCS12RABESTABLISH) AS PMSUMCS12RABESTABLISH,
                         SUM(UCELL3.PMSAMPLESBESTCS57RABESTABLISH) AS PMSAMPLESBESTCS57RABESTABLISH,
                         SUM(UCELL3.PMSUMBESTCS57RABESTABLISH) AS PMSUMBESTCS57RABESTABLISH,
                         SUM(UCELL3.PMSAMPLESBESTCS64RABESTABLISH) AS PMSAMPLESBESTCS64RABESTABLISH,
                         SUM(UCELL3.PMSUMBESTCS64RABESTABLISH) AS PMSUMBESTCS64RABESTABLISH,
                         SUM(UCELL3.PMSUMBESTDCHPSINTRABESTABLISH) AS PMSUMBESTDCHPSINTRABESTABLISH,
                         SUM(UCELL3.PMSAMPLEBESTDCHPSINTRABESTABLI) AS PMSAMPLEBESTDCHPSINTRABESTABLI,
                         SUM(UCELL3.PMSUMFACHPSINTRABESTABLISH) AS PMSUMFACHPSINTRABESTABLISH,
                         SUM(UCELL3.PMSAMPLEFACHPSINTRABESTABLISH) AS PMSAMPLEFACHPSINTRABESTABLISH,
                         SUM(UCELL3.PMSUMBESTPSHSADCHRABESTABLISH) AS PMSUMBESTPSHSADCHRABESTABLISH,
                         SUM(UCELL3.PMSAMPBESTPSHSADCHRABESTABLISH) AS PMSAMPBESTPSHSADCHRABESTABLISH,
                         SUM(UCELL3.PMSUMBESTPSEULRABESTABLISH) AS PMSUMBESTPSEULRABESTABLISH,
                         SUM(UCELL3.PMSAMPLBESTPSEULRABESTABLI) AS PMSAMPLBESTPSEULRABESTABLI,
                         SUM(UCELL4.PMSAMPLBESTAMR12200RABESTABLIS) AS PMSAMPLBESTAMR12200RABESTABLIS,
                         SUM(UCELL4.PMSUMBESTAMR12200RABESTABLISH) AS PMSUMBESTAMR12200RABESTABLISH,
                         SUM(UCELL4.PMSAMPLBESTAMR7950RABESTABLISH) AS PMSAMPLBESTAMR7950RABESTABLISH,
                         SUM(UCELL4.PMSUMBESTAMR7950RABESTABLISH) AS PMSUMBESTAMR7950RABESTABLISH,
                         SUM(UCELL4.PMSAMPLBESTAMR5900RABESTABLISH) AS PMSAMPLBESTAMR5900RABESTABLISH,
                         SUM(UCELL4.PMSUMBESTAMR5900RABESTABLISH) AS PMSUMBESTAMR5900RABESTABLISH,
                         SUM(UCELL4.PMSAMPLBESTAMR4750RABESTABLISH) AS PMSAMPLBESTAMR4750RABESTABLISH,
                         SUM(UCELL4.PMSUMBESTAMR4750RABESTABLISH) AS PMSUMBESTAMR4750RABESTABLISH

                    FROM EGW.TF_RNC_RAN_UCELL2 UCELL2

                         INNER JOIN
                         EGW.TF_RNC_RAN_UCELL3 UCELL3
                         ON UCELL2.DIA = UCELL3.DIA
                            AND UCELL2.HORA = UCELL3.HORA
                            AND UCELL2.RNC = UCELL3.RNC
                            AND UCELL2.MO = UCELL3.MO
                            AND UCELL2.MINUTO = UCELL3.MINUTO
                            AND UCELL2.UTRANCELL = UCELL3.UTRANCELL

                         INNER JOIN
                         EGW.TF_RNC_RAN_UCELL4 UCELL4
                         ON UCELL2.DIA = UCELL4.DIA
                            AND UCELL2.HORA = UCELL4.HORA
                            AND UCELL2.RNC = UCELL4.RNC
                            AND UCELL2.MO = UCELL4.MO
                            AND UCELL2.MINUTO = UCELL4.MINUTO
                            AND UCELL2.UTRANCELL = UCELL4.UTRANCELL

                         INNER JOIN
                         JANO.FECHAS FECHAS
                         ON UCELL2.DIA = FECHAS.FECHA

                         """ + hp_inner_join + """

                   WHERE UCELL2.DIA BETWEEN TO_DATE(%s, 'YYYY-MM-DD') AND TO_DATE(%s, 'YYYY-MM-DD')
                     AND UCELL2.HORA BETWEEN %s AND %s
                     AND UCELL2.RNC = %s
                     AND UCELL2.UTRANCELL = %s
                     AND FECHAS.DIASEM IN (%s,%s,%s,%s,%s,%s,%s) 
                     """ + holidays_filter + """

                GROUP BY UCELL2.DIA, UCELL2.HORA, UCELL2.RNC, UCELL2.UTRANCELL) TOTAL) CUSTOM

ORDER BY CUSTOM.DIA, CUSTOM.HORA        
"""
4

2 回答 2

3

好的,我找到了解决方案。在 Django 中,所有绑定参数都定义为字符串 (%s),因此当参数是数字时,会进行很多隐式转换。解决方案是使用子句TO_NUMBER(%s)中的函数将它们显式类型转换为数字。WHERE

于 2013-06-04T14:21:36.327 回答
1

您应该使用解释计划运行这两个查询以查看差异。我的猜测是,在字面参数的情况下,正在使用一个索引,而在绑定参数的情况下,它可能不会被使用。如果您可以看到两者之间的区别,您可能需要在您的选择语句中添加“提示”子句以强制选择正确的索引。您可以在此处阅读有关提示

如果您使用的是 sqlplus,您可以打开 autotrace 以显示解释计划和执行统计信息,例如:

SQL> set autotrace on
SQL> set linesize 200
SQL> set serveroutput on
SQL> spool foo.log
SQL> select count(*) from ucbcust; -- this is just a test table in my database. replace with your SQL.
SQL>   ... output shows...
SQL>  spool off


Output would look something like this (obviously, different for your query):



  Execution Plan
    ----------------------------------------------------------                                  
    Plan hash value: 1527793343                                                                                           ----------------------------------------------------------------------------------------          
    | Id  | Operation             | Name                   | Rows  | Cost (%CPU)| Time     |            

     ----------------------------------------------------------------------------------------         

| 0 | 选择声明 | | 1 | 3 (0)| 00:00:01 | 1 | 排序聚合 | | 1 | |
| 2 | 索引快速全扫描| UCBCUST_CUST_KEY_INDEX | 2088 | 3 (0)| 00:00:01

|                                                                                                    ----------------------------------------------------------------------------------------
    Statistics

              0  recursive calls                                                                                                                                                                            
              0  db block gets                                                                                                                                                                              
             17  consistent gets                                                                                                                                                                            
              0  physical reads                                                                                                                                                                             
              0  redo size                                                                                                                                                                                  
            343  bytes sent via SQL*Net to client                                                                                                                                                           
            364  bytes received via SQL*Net from client                                                                                                                                                     
              2  SQL*Net roundtrips to/from client                                                                                                                                                          
              0  sorts (memory)                                                                                                                                                                             
              0  sorts (disk)                                                                                                                                                                               
              1  rows processed                                                                                                                                                                             

要在 sqlplus 中以类似的方式执行参数化查询,您需要将变量定义为占位符,例如:

SQL> variable foo number
SQL> exec :foo := 1000

PL/SQL procedure successfully completed.

SQL> select :foo from dual
  2  /

      :FOO
----------
      1000

因此,在您的查询中,将所有“%*”参数替换为一个变量并在 Sqlplus 中运行以查看执行详细信息。希望通过这些工具,您会看到执行计划的不同。

于 2013-06-03T20:38:34.020 回答