2011-10-07 19 views
3

我遇到了一個查詢,在給定的 時間範圍內選擇記錄的問題。NHibernate和日期時間映射的問題

我從中選擇的列是DATE類型。我已將此 列映射爲DateTime屬性,並且查詢可以正常工作,但速度很慢。

生成的查詢是這樣的:(由NHProfiler提供)

select kifkalende0_.KALENDER_MEDARBEJDER_ID as KALENDER1_119_0_, 
    kifkalende1_.KALENDER_EMNE_ID  as KALENDER1_210_1_, 
    kifkalende0_.OPDATERET_TIDSPUNKT  as OPDATERET2_119_0_, 
    kifkalende0_.AENDRET     as AENDRET119_0_, 
    kifkalende0_.OPDATERET_AF   as OPDATERET4_119_0_, 
    kifkalende0_.OPRETTET_AF    as OPRETTET5_119_0_, 
    kifkalende0_.OPRETTET_TIDSPUNKT  as OPRETTET6_119_0_, 
    kifkalende0_.SLETTET     as SLETTET119_0_, 
    kifkalende0_.KALENDER_EMNE_ID  as KALENDER8_119_0_, 
    kifkalende0_.MEDARBEJDER_ID   as MEDARBEJ9_119_0_, 
    kifkalende1_.OPDATERET_TIDSPUNKT  as OPDATERET2_210_1_, 
    kifkalende1_.BESKRIVELSE    as BESKRIVE3_210_1_, 
    kifkalende1_.DATO     as DATO210_1_, 
    kifkalende1_.ER_FRA_SAG    as ER5_210_1_, 
    kifkalende1_.FRA_SAG_ID    as FRA6_210_1_, 
    kifkalende1_.FRA_TABEL    as FRA7_210_1_, 
    kifkalende1_.FRA_TID     as FRA8_210_1_, 
    kifkalende1_.OPDATERET_AF   as OPDATERET9_210_1_, 
    kifkalende1_.OPRETTET_AF    as OPRETTET10_210_1_, 
    kifkalende1_.OPRETTET_TIDSPUNKT  as OPRETTET11_210_1_, 
    kifkalende1_.SAG_TYPE    as SAG12_210_1_, 
    kifkalende1_.TIL_TID     as TIL13_210_1_, 
    kifkalende1_.YDERLIGERE_BESKRIVELSE as YDERLIGERE14_210_1_, 
    kifkalende1_.EMNE_ID     as EMNE15_210_1_, 
    kifkalende1_.PERSON_ID    as PERSON16_210_1_ 
from "KIF_KALENDER_MEDARBEJDER" kifkalende0_ 
    left outer join "KIF_KALENDER_EMNE" kifkalende1_ on 
kifkalende0_.KALENDER_EMNE_ID = kifkalende1_.KALENDER_EMNE_ID, 
    "KIF_KALENDER_EMNE" kifkalende2_ 
where kifkalende0_.KALENDER_EMNE_ID = kifkalende2_.KALENDER_EMNE_ID 
    and (kifkalende0_.MEDARBEJDER_ID in (7624 /* :p3 */,6226 
/* :p4 */,7382 /* :p5 */,5774 /* :p6 */, 5775 /* :p7 */,8259 
/* :p8 */,8218 /* :p9 */,9899 /* :p10 */, 6000 /* :p11 */,5779 
/* :p12 */,5780 /* :p13 */,5782 /* :p14 */, 5783 /* :p15 */,5784 
/* :p16 */,5785 /* :p17 */,5788 /* :p18 */, 5789 /* :p19 */,5790 
/* :p20 */,7341 /* :p21 */,8963 /* :p22 */, 10201 /* :p23 */,10388 
/* :p24 */))  
and kifkalende2_.DATO >= TIMESTAMP '2010-11-10 00:00:00.00' /* :p0 */ 
and kifkalende2_.DATO <= TIMESTAMP '2010-11-10 23:59:59.00' /* :p1 */ 
and (kifkalende0_.SLETTET = TIMESTAMP '1899-12-31 00:00:00.00' /* :p2 */ 
    or kifkalende0_.SLETTET is null); 

而在我們的數據庫中,它需要圍繞1500毫秒來執行。

如果我們手動更改查詢:

select kifkalende0_.KALENDER_MEDARBEJDER_ID as KALENDER1_119_0_, 
    kifkalende1_.KALENDER_EMNE_ID  as KALENDER1_210_1_, 
    kifkalende0_.OPDATERET_TIDSPUNKT  as OPDATERET2_119_0_, 
    kifkalende0_.AENDRET     as AENDRET119_0_, 
    kifkalende0_.OPDATERET_AF   as OPDATERET4_119_0_, 
    kifkalende0_.OPRETTET_AF    as OPRETTET5_119_0_, 
    kifkalende0_.OPRETTET_TIDSPUNKT  as OPRETTET6_119_0_, 
    kifkalende0_.SLETTET     as SLETTET119_0_, 
    kifkalende0_.KALENDER_EMNE_ID  as KALENDER8_119_0_, 
    kifkalende0_.MEDARBEJDER_ID   as MEDARBEJ9_119_0_, 
    kifkalende1_.OPDATERET_TIDSPUNKT  as OPDATERET2_210_1_, 
    kifkalende1_.BESKRIVELSE    as BESKRIVE3_210_1_, 
    kifkalende1_.DATO     as DATO210_1_, 
    kifkalende1_.ER_FRA_SAG    as ER5_210_1_, 
    kifkalende1_.FRA_SAG_ID    as FRA6_210_1_, 
    kifkalende1_.FRA_TABEL    as FRA7_210_1_, 
    kifkalende1_.FRA_TID     as FRA8_210_1_, 
    kifkalende1_.OPDATERET_AF   as OPDATERET9_210_1_, 
    kifkalende1_.OPRETTET_AF    as OPRETTET10_210_1_, 
    kifkalende1_.OPRETTET_TIDSPUNKT  as OPRETTET11_210_1_, 
    kifkalende1_.SAG_TYPE    as SAG12_210_1_, 
    kifkalende1_.TIL_TID     as TIL13_210_1_, 
    kifkalende1_.YDERLIGERE_BESKRIVELSE as YDERLIGERE14_210_1_, 
    kifkalende1_.EMNE_ID     as EMNE15_210_1_, 
    kifkalende1_.PERSON_ID    as PERSON16_210_1_ 
from "KIF_KALENDER_MEDARBEJDER" kifkalende0_ 
    left outer join "KIF_KALENDER_EMNE" kifkalende1_ on 
kifkalende0_.KALENDER_EMNE_ID = kifkalende1_.KALENDER_EMNE_ID, 
    "KIF_KALENDER_EMNE" kifkalende2_ 
where kifkalende0_.KALENDER_EMNE_ID = kifkalende2_.KALENDER_EMNE_ID 
    and (kifkalende0_.MEDARBEJDER_ID in (7624 /* :p3 */,6226 
/* :p4 */,7382 /* :p5 */,5774 /* :p6 */, 5775 /* :p7 */,8259 
/* :p8 */,8218 /* :p9 */,9899 /* :p10 */, 6000 /* :p11 */,5779 
/* :p12 */,5780 /* :p13 */,5782 /* :p14 */, 5783 /* :p15 */,5784 
/* :p16 */,5785 /* :p17 */,5788 /* :p18 */, 5789 /* :p19 */,5790 
/* :p20 */,7341 /* :p21 */,8963 /* :p22 */, 10201 /* :p23 */,10388 
/* :p24 */)) 
    and kifkalende2_.DATO>=to_date('10-11-2010 00:00:00', 'DD-MM-YYYY HH24:MI:SS') 
    and kifkalende2_.DATO<=to_date('10-11-2010 23:59:59', 'DD-MM-YYYY HH24:MI:SS') 
    and (kifkalende0_.SLETTET=to_date('31-12-1899 00:00:00', 'DD-MM-YYYY HH24:MI:SS') 
    or kifkalende0_.SLETTET is null); 

它執行50ms左右。

有什麼辦法讓NHibernate生成to_date而不是 時間戳用於日期比較?

我一樣的RegisterDateTimeTypeMappings如何在 的Oracle10gDialect有點混亂,但我想擴展它,改變方法

  protected override void RegisterDateTimeTypeMappings() 
      { 
        RegisterColumnType(DbType.Date, "DATE"); 
        //RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); 
        RegisterColumnType(DbType.DateTime, "DATE"); 
        RegisterColumnType(DbType.Time, "TIMESTAMP(4)"); 
      } 

,但沒有幫助。

我們的環境是:

  • .NET(C#)4.0
  • NHibernate的3.1.0,主要經由LINQ的
  • ODP.Net 11.2.2.0使用針對的Oracle 11g

有沒有人有任何建議?

感謝, ./Daniel

回答

6

我通過覆蓋下面的NHibernate類來解決我的問題和你的問題。 NHProfiler仍將顯示一個TIMESTAMP值,但底層參數將是DATE類型 - 如果您的oracle列也是DateTime,它將是可索引的。 將鼠標懸停在NHProfiler中的參數上,查看我的意思 - 例如: :p0:TIMESTAMP - '2011-07-01 00:00:00.00'日期 而不是 :p0:TIMESTAMP - '2011-07 -01 00:00:00.00'時間戳。

我也使用Oracle 11g,C#.Net 4,Nhibernate 3.2。

public class OracleDataClientDriver2 : OracleDataClientDriver 
{ 
    protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType) 
    { 
     switch (sqlType.DbType) 
     { 
       //Timestamp columns not indexed by Oracle 11g date columns. - Use Date 
      case DbType.DateTime: 
       base.InitializeParameter(dbParam, name, SqlTypeFactory.Date); 
       break; 
      default: 
       base.InitializeParameter(dbParam, name, sqlType); 
       break; 
     } 
    } 
} 
-1

應該不會出現任何轉換在所有如果參數是正確的類型。只有在字符串類型中有時間戳時才需要TIMESTAMP或to_date()。如果參數輸入正確,應該這樣寫:

select 
     tab.COL as col 
    from 
     TABLE tab 
    where 
     tab.COL = :p0; 
:p0 = 01.01.2000 00:00:00 [Type: DateTime (0)] 

因此,請確保您傳遞DateTime對象查詢。

+0

在我的查詢和映射中,它們是DateTime對象。我發佈的SQL是Oracle收到的SQL。 NHibernate或ODP。NET處理.net和SQL之間的轉換。 – dajoni

+0

@Djn檢查直接來自NHibernate的SQL輸出(通過NHibernate.SQL記錄器或控制檯輸出)而不是NHProf輸出。它應該看起來像我發佈的那個。 – cremor

+0

事實上,我的查詢看起來是一樣的,並將.net類型添加到參數名稱中。無法理解爲什麼它如此之慢,我使用NHprofiler來獲得解析的sql。 我的情況看起來有點像[this](http://stackoverflow.com/questions/2464502/avoid-implicit-conversion-from-date-to-timestamp-for-selects-with-oracle-usinghi ),但我無法將一些建議與我們的環境相匹配。 – dajoni