2014-02-22 42 views
0

我正在使用C#(sharpdevelop)來訪問Firebird 2.5服務器。這工作得很好。但是,我遇到了性能問題。 我有兩個表,會員和交易存儲誰買什麼時候。看看誰在當我運行下面的複合查詢沒有被激活:C#上的火鳥:FbCommand.ExecuteReader()性能

SELECT * FROM members M 
WHERE exists (select 1 from transactions WHERE taDateTime >= '30.06.2013' and Memberid = M.ID) 

因此,會員制表上域ID和內幕交易的主要指標有兩個taDateTime和MEMBERID的indeces。

myConnection = new FbConnection(myConnectionString); 
Connection.Open(); 

// property of a helper class, uses myConnection 
// Then when I press the Search button: 
// create the sql command, because the cut-off date is passed as a dbParam 
IDbCommand aCmd = new FbCommand(sql, Connection); 
IDataReader aReader = aCmd.ExecuteReader(); 

我現在有幾個10'000條目在成員和幾個100'000條目在交易。如果我在flamerobin中運行此查詢,則需要大約2.6秒的時間才能運行。這並不令人興奮,但足夠。但是,如果我在C#中運行此查詢,則需要3分鐘才能從調用 FbCommand.ExecuteReader(sql)返回。 我還沒有打開結果集,這純粹是對ExecuteReader()的調用。那要花多久呢?

我已經嘗試了其他幾件事情,通過添加ROWSFIRST子句來限制結果數量,兩者都沒有任何影響。所以這不是重要的結果數量。 我試圖將呼叫拆分爲2個查詢:首先找到DISTINCT(Transaction.MemberID),然後找到適合的成員,但是有太多ID合理地傳遞到第二個查詢中。 我甚至編寫了一個循環,它首先找到MemberID,然後爲每個結果運行一個"SELECT * FROM Members where ID = xx",這比單個語句快。那麼,什麼使得對ExecuteReader的調用延遲這麼久?

請幫忙,我在這裏真的很茫然。

親切的問候, 漢納斯

+0

您使用哪種事務隔離? –

+0

在等待結果的同時,您是否查看了[MON $ tables](http://ibexpert.net/ibe/index.php?n=Doc.SystemObjects#MONSystemTables)以查看數據庫中發生了什麼?您可以在MON $ STATEMENTS中看到當前正在執行和閒置的語句。 – nater

+0

Hiya,我一次只運行一次交易,所以我希望這不重要,因爲我從來沒有看過那:)如果我錯了,請糾正我。關於MON $表:他們看起來很有趣,我可以從他們身上學到什麼?閒置聲明?什麼時候會發生?是否有可能看到我通過的優化聲明?我很想看看flamerobin如何優化我的陳述,也許這解釋了該代碼的性能與代碼之間的差異... – user1766553

回答

0

我應該通過註釋,而不是發佈一個答案澄清了這一點,但是,作爲一個新手,我不能要求更多的信息(即評論)!

引述你行「看到誰沒有在一段時間我運行下面的複合查詢積極:」在我看來,在這種情況下正確的查詢應該是...

SELECT * FROM members M 
where M.ID not in (select distinct memberid from transactions WHERE taDateTime >= '30.06.2013') 

你寫的查詢會給你活躍的人。另外,它會加載數據庫服務器,處理幾條10,000 * 100,000條記錄。

如果你確實在尋找不活躍在某個日期後的人,我給你的查詢應該給你至少100倍的結果,然後是以前的結果。我很想知道結果,無論如何請讓我知道。謝謝。

+0

嗨!你是對的。我的編程允許搜索活動和非活動,所以有時我使用NOT,有時候使用我寫的語句。對困惑感到抱歉。但是要回答你真正的問題:我發現select distinct ...語句的速度比存在的變體慢20倍。我原本使用過這個,但是發現了一個關於網絡某處的性能的解釋,推薦使用EXIST變體,因爲另一個不使用現有的變量,因此速度較慢... – user1766553

+0

這可能在今天,但被警告內部Firebird將「不在()」翻譯成一個大的<>語句。當它執行時,它將執行如下所示:「(m.id <> memberid1和m.id <> memberid2和m.id <> memberid3 ...)」。有一個[語句大小限制](http://www.firebirdfaq。org/faq197 /),並且有一天,您的獨特子查詢可能會返回足夠的MemberId來達到此限制。火鳥會舉一個例外。一個相關的子查詢(使用「不存在」,OP建議)是去IMO的方式。 – nater

0

我同意@Ravi您的查詢本身有一些可能需要平滑的邊緣。在SQL中我不夠好,不能真正預測發生了什麼,但從我的直覺中我會說你的聲明對我來說看起來「可疑」...

但是,那還是不能回答你的問題,否則Flamerobin中的執行時間與從代碼執行時一樣糟糕。出於這個原因,我希望你的代碼中的某些東西成爲罪魁禍首。如果你能用更多的代碼更新你的文章,這將是非常好的。

需要考慮的事情:

  • 是數據庫連接已經打開?打開連接是非常昂貴的性能。
  • 您是否已激活連接池?重用連接顯着提高了性能。
  • 是否有其他資源密集型任務/線程或同時運行? 或者當您執行該語句時,是否還有其他對數據庫的讀取/寫入訪問同時運行?可能有幾個訪問正在等待彼此完成。
  • 您是否將查詢結果綁定到您的用戶界面?這裏有數百個潛在的性能瓶頸。
  • 此外,如果您有手邊的分析器,請查看執行計劃。該聲明是否使用索引?還是它執行全表掃描(或任何奇怪的事情可能發生)?
  • 您是否在執行前執行了命令Prepare()?如果你在數據庫中多次觸發它,這也會帶來性能上的提升。

不要忘記,由於.NET代碼在JIT編譯器執行時需要進行初始化和分配,因此當您的語句再次運行時,它的運行速度可能會更快。嘗試此操作,並在第一次查詢後第二次(或多次)運行您的查詢。它有什麼區別?

+0

嗨延斯,感謝您的意見。回答你的觀點:是的,連接已經打開並且沒有,當時沒有其他查詢正在運行。結果不會綁定到任何UI元素,我手動執行。該聲明只被解僱一次,所以Prepare()不會幫助我。 Indeces的使用不正確,但這是firebird中子查詢的一個已知「特性」。這就是我使用EXISTS而不是Ravi引用的整潔語句來轉換爲怪異聲明的原因。但我測試了各種各樣的flamerobin變體,而奇怪的變體是迄今最快的。 – user1766553

+0

@ user1766553:謝謝你的澄清。我仍然懷疑你的代碼。否則Flamerobin不可能如此快速。你可以請張貼一些代碼嗎? –

+0

早先編: \t myConnection = new FbConnection(myConnectionString); \t Connection.Open();一個輔助類的//屬性,使用MyConnection的 後來,當我按下搜索按鈕: \t //創建SQL命令,因爲截止日期爲dbParam \t IDbCommand的ACMD =新FbCommand(SQL,通過連接); \t IDataReader aReader = aCmd.ExecuteReader(); 這是最後一行,需要3分鐘 – user1766553

0

感謝所有的投入,夥計們!在你的建議中搜索一些關鍵字使得我更詳細地分析我的查詢,從而發現錯誤:我的編「祕密地」在查詢結尾添加了一個「ORDER BY Member.Name」子句,這是罪魁禍首。我一定是一直在看着我的眼皮想念:)無論如何,我發現了一個非常有用的文章,用於理解和調整firebird中的查詢,只能將它推薦給任何感興趣的人:http://conferences.embarcadero.com/article/32256。親切的問候,Hannes