2016-11-10 126 views
0

我試圖用一些參數執行查詢。 如果我使用文字參數在pl/sql developer(oracle)中執行這個sql它在1秒內運行。 如果我使用java,jdbc驅動程序和文字參數執行這個sql它運行速度也非常快。例如,使用此代碼:在Java中綁定變量的SQL查詢需要很長時間

String query = "select ID, (a lot of other columns)" 
      + " from VCP_TIT_LIQDC" 
      + " WHERE" 
      + " ((123 is not null and id_tit = 123 and exists" 
      + " (select 1 from sd_dual" 
      + " where ((exists" 
      + " (select 1" 
      + " from fn_config_usr cfg" 
      + " where cfg.nome_usr_bd = 'NAME' and cfg.ind_acesso_qualquer_site = 'S') or exists" 
      + " (select 1" 
      + " from fn_rel_usr_site rel" 
      + " where rel.nome_usr_bd = 'NAME' and rel.cod_site = decode(vcp_tit_liqdc.id_empresa_lider, null, vcp_tit_liqdc.cod_site, vcp_tit_liqdc.cod_site_empresa_lider)))))) OR" 
      + " (123 is null and (28 is null or" 
      + " ((id_empresa = nvl(28 ,id_empresa) and id_empresa_lider is null) OR" 
      + " id_empresa_lider = 28)) AND decode (id_empresa_lider, null, cod_site, cod_site_empresa_lider) in" 
      + " (select nvl (null , site.cod_site)" 
      + " from fn_site site, fn_rel_usr_site rus, fn_config_usr cfg" 
      + " where cfg.nome_usr_bd = 'NAME' and rus.nome_usr_bd (+) = cfg.nome_usr_bd and site.cod_site = decode (cfg.ind_acesso_qualquer_site, 'S', site.cod_site, rus.cod_site) group by site.cod_site))) AND (usr_cadastro = 'NAME' or (id_tit in" 
      + " (select ac.id_tit" 
      + " from cp_titulo_acesso ac, cp_usr_acesso_janela jan" 
      + " where ac.id_acesso = jan.id_acesso and 'WINDOW' = nvl(jan.nome_janela_sis, 'WINDOW') and jan.nome_usr_bd = 'NAME'))) ORDER BY ID_TIT DESC"; 

    PreparedStatement p = connection.prepareStatement(query); 
    ResultSet rs = p.executeQuery(); 

但是,如果我使用「?」設置參數, (綁定)運行需要10分鐘或更長時間。例如在代碼中:

String query = "select ID, (a lot of other columns)" 
      + " from VCP_TIT_LIQDC" 
      + " WHERE" 
      + " ((? is not null and id_tit = ? and exists" 
      + " (select 1 from sd_dual" 
      + " where ((exists" 
      + " (select 1" 
      + " from fn_config_usr cfg" 
      + " where cfg.nome_usr_bd = ? and cfg.ind_acesso_qualquer_site = 'S') or exists" 
      + " (select 1" 
      + " from fn_rel_usr_site rel" 
      + " where rel.nome_usr_bd = ? and rel.cod_site = decode(vcp_tit_liqdc.id_empresa_lider, null, vcp_tit_liqdc.cod_site, vcp_tit_liqdc.cod_site_empresa_lider)))))) OR" 
      + " (? is null and (? is null or" 
      + " ((id_empresa = nvl(? ,id_empresa) and id_empresa_lider is null) OR" 
      + " id_empresa_lider = ?)) AND decode (id_empresa_lider, null, cod_site, cod_site_empresa_lider) in" 
      + " (select nvl (? , site.cod_site)" 
      + " from fn_site site, fn_rel_usr_site rus, fn_config_usr cfg" 
      + " where cfg.nome_usr_bd = ? and rus.nome_usr_bd (+) = cfg.nome_usr_bd and site.cod_site = decode (cfg.ind_acesso_qualquer_site, 'S', site.cod_site, rus.cod_site) group by site.cod_site))) AND (usr_cadastro = ? or (id_tit in" 
      + " (select ac.id_tit" 
      + " from cp_titulo_acesso ac, cp_usr_acesso_janela jan" 
      + " where ac.id_acesso = jan.id_acesso and ? = nvl(jan.nome_janela_sis, ?) and jan.nome_usr_bd = ?))) ORDER BY ID_TIT DESC"; 

    PreparedStatement p = connection.prepareStatement(query); 

    p.setInt(1, 123); 
    p.setInt(2, 123); 
    p.setString(3, "NAME"); 
    p.setString(4, "NAME"); 
    p.setInt(5, 123); 
    p.setInt(6, 28); 
    p.setInt(7, 28); 
    p.setInt(8, 28); 
    p.setString(9, null); 
    p.setString(10, "NAME"); 
    p.setString(11, "NAME"); 
    p.setString(12, "WINDOW"); 
    p.setString(13, "WINDOW"); 
    p.setString(14, "NAME"); 

    ResultSet rs = p.executeQuery(); 

有什麼辦法可以解決這個問題嗎?因爲sql在每種情況下都是相同的。

我正在使用10g數據庫並測試了jdbc的這個版本:10.2.0.1.0,11.2.0.2.0和12.1.0.2.0。

+4

性能差異幾乎可以肯定與JDBC沒有關係,而是與Oracle優化程序使用的信息相比,當它提供文字時的信息要少得多。要遵循最佳實踐,您不需要用綁定變量替換每個文字。您只需要替換將從一次執行更改爲另一次執行的文字。 「NAME」,「WINDOW」等在每個查詢運行中看起來都是相同的。首先嚐試僅綁定在運行時更改的文字,並查看是否有幫助。它可能也可能不會。 –

+0

我需要在運行時設置這些變量,因爲這些變量來自用戶。 – computered

+0

由於在WHERE子句中使用了其中一些字符串參數,因此我傾向於調查參數值是否以如下方式傳遞:實際執行計劃無法使用任何可用索引並被強制執行一個或更多的表掃描。 [此處]的某些信息(http://docs.oracle.com/cd/B19306_01/server.102/b14225/ch7progrunicode.htm#i1006858)可能有助於確定是否屬於這種情況。 –

回答

1

包含靜態值的查詢具有謂詞,如"123 is null and (28 is null"使用靜態值,優化器知道這些條件從不爲真,因此可以簡單地忽略它們。作爲一個比喻,如果你被告知去商店買一條條紋油漆,你馬上就可以看到沒有任何意義,因爲沒有這樣的事情。

當它們是實際變量時,它們有可能是空的,所以需要做大量額外的工作。

您可能最好在Java代碼中測試null-ness的一些值,並構建一個更簡單的查詢來執行。

+0

嗨加里,檢查它,我們已經測試了使用綁定在一個SQL腳本(沒有Java)。例如,使用這種類型的代碼(:cod_tit爲空和...)。這個腳本運行速度非常快。顯然,問題發生在使用java和jdbc。 – computered