Sql 提高select语句的性能

Sql 提高select语句的性能,sql,oracle,sql-tuning,Sql,Oracle,Sql Tuning,我有一个选择性能问题,如何使这个SQL更有效 SELECT O.DT_OCORRENCIA, S.NU_SMP, CLI.NM_APELIDO CLI, TRANS.NM_ENTIDADE TRANS, TPO.DS_TIPO_OCORRENCIA, O.DS_OCORRENCIA, REPLACE(FNC_RETORNA_MOTORISTAS(S.CD_SMP), '<br>', ';') AS NOME_MOTORISTA, OG.DS_NOME AS DS_NO

我有一个选择性能问题,如何使这个SQL更有效

SELECT
 O.DT_OCORRENCIA,
 S.NU_SMP,
 CLI.NM_APELIDO CLI,
 TRANS.NM_ENTIDADE TRANS,
 TPO.DS_TIPO_OCORRENCIA,
 O.DS_OCORRENCIA,
 REPLACE(FNC_RETORNA_MOTORISTAS(S.CD_SMP), '<br>', ';') AS NOME_MOTORISTA,
 OG.DS_NOME AS DS_NOME_ORIGEM,
 DG.DS_NOME AS DS_NOME_DESTINO,
 U.NM_LOGIN AS DS_USUARIO_OCORRENCIA,
 CASE
   WHEN O.CD_USUARIO_INFORMOU = 717 THEN
    'NAO'
   ELSE
    'SIM'
 END FL_MANUAL,
 CASE
   WHEN (O.FL_ENVIOU_EMAIL_CLIENTE = 'S' OR O.FL_ENVIOU_EMAIL_TRANSP = 'S') THEN
    'SIM'
   ELSE
    'NÃO'
 END ENVIOU_EMAIL,
 DECODE(O.NU_LOCAL_OCORRENCIA,
        '1',
        'Origem',
        '2',
        'Em transito',
        '3',
        'Alvos',
        '4',
        'Indiferente') DS_LOCAL_OCORRENCIA,
 TOPER.DS_TIPO_OPERACAO
  FROM TB_SMP S
 INNER JOIN TB_OCORRENCIA O
    ON O.CD_SMP = S.CD_SMP
 INNER JOIN TB_TIPO_OCORRENCIA TPO
    ON O.CD_TIPO_OCORRENCIA = TPO.CD_TIPO_OCORRENCIA
  LEFT JOIN TB_TIPO_OPERACAO TOPER
    ON TOPER.CD_TIPO_OPERACAO = S.CD_TIPO_OPERACAO
  LEFT JOIN TB_USUARIO U
    ON U.CD_USUARIO = O.CD_USUARIO_INFORMOU
  LEFT JOIN TB_ENTIDADE CLI
    ON CLI.CD_ENTIDADE = S.CD_ENTIDADE_CLIENTE
  LEFT JOIN TB_ENTIDADE TRANS
    ON TRANS.CD_ENTIDADE = S.CD_ENTIDADE_TRANSPORTADOR
  LEFT JOIN TB_PONTO_GEOREFERENCIADO OG
    ON OG.CD_PONTO_GEOREFERENCIADO = S.CD_PONTO_GEO_ORIGEM
  LEFT JOIN TB_PONTO_GEOREFERENCIADO DG
    ON (S.CD_PONTO_GEO_DESTINO IS NULL AND
       DG.CD_PONTO_GEOREFERENCIADO =
       FNC_GET_ULTIMA_ENTREGA_PONTO(S.CD_SMP))
    OR (S.CD_PONTO_GEO_DESTINO IS NOT NULL AND
       DG.CD_PONTO_GEOREFERENCIADO = S.CD_PONTO_GEO_DESTINO)

 WHERE EXISTS (SELECT 1
          FROM TB_TIPO_OCORRENCIA T
         WHERE T.CD_TIPO_OCORRENCIA = O.CD_TIPO_OCORRENCIA)

   AND S.DT_CADASTRO BETWEEN to_date('21/04/2014', 'dd/MM/yyyy') AND to_date('09/06/2014', 'dd/MM/yyyy')
   AND O.DT_OCORRENCIA BETWEEN to_date('10/05/2014','dd/MM/yyyy') AND to_date('20/05/2014','dd/MM/yyyy')
   AND S.cd_tipo_operacao in
       (-1, 27, 11, 13, 37, 6, 7, 21, 12, 36, 28, 4, 5)

-- order by using linq?
 ORDER BY CLI.NM_APELIDO,
          TRANS.NM_APELIDO,
          O.DT_OCORRENCIA,
          DS_TIPO_OCORRENCIA
我的执行计划如下:


注:我对sql tunnig一无所知:

在对这些表进行内部联接时,可以将一些WHERE条件移动到联接条件,如下所示。然后,在左边的连接条件下,您将在较小的数据集上操作

SELECT
 O.DT_OCORRENCIA,
 S.NU_SMP,
 CLI.NM_APELIDO CLI,
 TRANS.NM_ENTIDADE TRANS,
 TPO.DS_TIPO_OCORRENCIA,
 O.DS_OCORRENCIA,
 REPLACE(FNC_RETORNA_MOTORISTAS(S.CD_SMP), '<br>', ';') AS NOME_MOTORISTA,
 OG.DS_NOME AS DS_NOME_ORIGEM,
 DG.DS_NOME AS DS_NOME_DESTINO,
 U.NM_LOGIN AS DS_USUARIO_OCORRENCIA,
 CASE
   WHEN O.CD_USUARIO_INFORMOU = 717 THEN
    'NAO'
   ELSE
    'SIM'
 END FL_MANUAL,
 CASE
   WHEN (O.FL_ENVIOU_EMAIL_CLIENTE = 'S' OR O.FL_ENVIOU_EMAIL_TRANSP = 'S') THEN
    'SIM'
   ELSE
    'NÃO'
 END ENVIOU_EMAIL,
 DECODE(O.NU_LOCAL_OCORRENCIA,
        '1',
        'Origem',
        '2',
        'Em transito',
        '3',
        'Alvos',
        '4',
        'Indiferente') DS_LOCAL_OCORRENCIA,
 TOPER.DS_TIPO_OPERACAO
  FROM TB_SMP S
 INNER JOIN TB_OCORRENCIA O
    ON O.CD_SMP = S.CD_SMP
   AND S.DT_CADASTRO BETWEEN to_date('21/04/2014', 'dd/MM/yyyy') AND to_date('09/06/2014', 'dd/MM/yyyy')
   AND O.DT_OCORRENCIA BETWEEN to_date('10/05/2014','dd/MM/yyyy') AND to_date('20/05/2014','dd/MM/yyyy')
   AND S.cd_tipo_operacao in
       (-1, 27, 11, 13, 37, 6, 7, 21, 12, 36, 28, 4, 5)
 INNER JOIN TB_TIPO_OCORRENCIA TPO
    ON O.CD_TIPO_OCORRENCIA = TPO.CD_TIPO_OCORRENCIA
  LEFT JOIN TB_TIPO_OPERACAO TOPER
    ON TOPER.CD_TIPO_OPERACAO = S.CD_TIPO_OPERACAO
  LEFT JOIN TB_USUARIO U
    ON U.CD_USUARIO = O.CD_USUARIO_INFORMOU
  LEFT JOIN TB_ENTIDADE CLI
    ON CLI.CD_ENTIDADE = S.CD_ENTIDADE_CLIENTE
  LEFT JOIN TB_ENTIDADE TRANS
    ON TRANS.CD_ENTIDADE = S.CD_ENTIDADE_TRANSPORTADOR
  LEFT JOIN TB_PONTO_GEOREFERENCIADO OG
    ON OG.CD_PONTO_GEOREFERENCIADO = S.CD_PONTO_GEO_ORIGEM
  LEFT JOIN TB_PONTO_GEOREFERENCIADO DG
    ON (S.CD_PONTO_GEO_DESTINO IS NULL AND
       DG.CD_PONTO_GEOREFERENCIADO =
       FNC_GET_ULTIMA_ENTREGA_PONTO(S.CD_SMP))
    OR (S.CD_PONTO_GEO_DESTINO IS NOT NULL AND
       DG.CD_PONTO_GEOREFERENCIADO = S.CD_PONTO_GEO_DESTINO)
-- order by using linq?
 ORDER BY CLI.NM_APELIDO,
          TRANS.NM_APELIDO,
          O.DT_OCORRENCIA,
          DS_TIPO_OCORRENCIA;

您可以删除WHERE EXISTS从TB_TIPO_OCORRENCIA T中选择1,其中T.CD_TIPO_OCORRENCIA=O.CD_TIPO_OCORRENCIA,因为您已经在较早的时候内部加入TB_OCORRENCIA和TB_TIPO_OCORRENCIA。Oracle是否将时间存储为日期类型的一部分?然后要避免“是”,这适用于具有连续范围类型的所有系统。我很好奇您是否可以按顺序将DS_TIPO_OCORRENCIA切换到O.DS_OCORRENCIA。同一个表通常意味着使用索引的可能性更大。。。。我通常建议只将这些条件移动到直接引用该表的联接。当表格位于FROM子句中时,在WHERE子句中保留仅引用该表格的条件。对于BETWEEN条件,RDBMS可能会自动执行此操作,因此在这种情况下可能不会获得任何好处。对于内部联接,条件是在on子句中还是在where子句中应该有所不同。Oracle优化器做得相当好。
TB_SMP.DT_CADASTRO
TB_SMP.cd_tipo_operacao
TB_OCORRENCIA.DT_OCORRENCIA
TB_ENTIDADE.CD_ENTIDADE