2015-10-17 110 views
0

我正在使用一個接口在WinForm應用程序中顯示來自DBF文件的數據。 我開始使用OdbcConnection。儘管有效,但由於Visual FoxPro驅動程序的某些限制(子查詢不受支持),因此我使用OLEDB(VFPOLEDB)打開。現在我可以運行復雜的查詢,但是出現了新的問題需要解決。問題是這些查詢太慢了。比預期的要慢100倍。使用OLEDB(VFPOLEDB)在DBF文件上運行查詢太慢

下面是演示代碼。 有一個DBF表「PROD」。索引字段PRICE_N用於查詢的Where子句中。該表位於運行應用程序的同一臺PC上。正如您所看到的,通過ODBC(Microsoft Visual FoxPro Driver)和OLEDB(VFPOLEDB)運行查詢所花費的時間差別很大。

  TimeSpan timeSpanODBC; 
     DateTime timeODBC = DateTime.Now; 

     OdbcConnection odbcConnection = new OdbcConnection(@"Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=C:\Users\Vakshul\Documents\dbfs;Exclusive=No;Collate=Machine;NULL=NO;DELETED=NO;BACKGROUNDFETCH=NO;"); 
     odbcConnection.Open(); 
     OdbcCommand odbcCommand = new OdbcCommand("SELECT utk_ved FROM prod WHERE (price_n='641857')", odbcConnection); 
     odbcCommand.ExecuteScalar(); 
     timeSpanODBC = DateTime.Now - timeODBC; 
     double timeOdbcEqual = timeSpanODBC.TotalMilliseconds; 
     System.Console.WriteLine("Time spent via ODBC(milliseconds) using '=' to compare - {0}", timeOdbcEqual.ToString()); 


     timeODBC = DateTime.Now; 

     odbcCommand = new OdbcCommand("SELECT utk_ved FROM prod WHERE (price_n like'641857')", odbcConnection); 
     odbcCommand.ExecuteScalar(); 
     timeSpanODBC = DateTime.Now - timeODBC; 
     double timeOdbcLike = timeSpanODBC.TotalMilliseconds; 
     System.Console.WriteLine("Time spent via ODBC(milliseconds) using 'Like' to compare - {0}", timeOdbcLike.ToString()); 

     TimeSpan timeSpanOLEDB; 
     DateTime timeOLEDB = DateTime.Now; 

     OleDbConnection oleDbCon = new OleDbConnection(@"Provider=VFPOLEDB.1;Data Source=C:\Users\Vakshul\Documents\dbfs;Collating Sequence=MACHINE;Mode=Read"); 
     oleDbCon.Open(); 
     OleDbCommand oleDbcommand = new OleDbCommand("SELECT utk_ved FROM prod WHERE (price_n = '641857')", oleDbCon); 
     oleDbcommand.ExecuteScalar(); 
     timeSpanOLEDB = DateTime.Now - timeOLEDB; 
     double timeOLEDBEqual = timeSpanOLEDB.TotalMilliseconds; 
     System.Console.WriteLine("Time spent via OLEDB(milliseconds) using '=' to compare - {0}", timeOLEDBEqual.ToString()); 

     timeOLEDB = DateTime.Now; 

     oleDbcommand = new OleDbCommand("SELECT utk_ved FROM prod WHERE (price_n like '641857')", oleDbCon); 
     oleDbcommand.ExecuteScalar(); 
     timeSpanOLEDB = DateTime.Now - timeOLEDB; 
     double timeOLEDLike = timeSpanOLEDB.TotalMilliseconds; 
     System.Console.WriteLine("Time spent via OLEDB(milliseconds) using 'Like' to compare - {0}", timeOLEDLike.ToString()); 

     System.Console.WriteLine("ODBC is faster than OLEDB {0} times using '=' to compare", Math.Round(timeOLEDBEqual/timeOdbcEqual, 0)); 
     System.Console.WriteLine("ODBC is faster than OLEDB {0} times using 'Like' to compare", Math.Round(timeOLEDBEqual/timeOdbcEqual, 0)); 

控制檯,在第一次運行後:

Time spent via ODBC(milliseconds) using '=' to compare - 5,0006 
Time spent via ODBC(milliseconds) using 'Like' to compare - 3,5005 
Time spent via OLEDB(milliseconds) using '=' to compare - 1630,207 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 1755,2228 
ODBC is faster than OLEDB 326 times using '=' to compare 
ODBC is faster than OLEDB 326 times using 'Like' to compare 

Console, after the second run: 
Time spent via ODBC(milliseconds) using '=' to compare - 4,5006 
Time spent via ODBC(milliseconds) using 'Like' to compare - 4,5005 
Time spent via OLEDB(milliseconds) using '=' to compare - 1526,1938 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 1595,2026 
ODBC is faster than OLEDB 339 times using '=' to compare 
ODBC is faster than OLEDB 339 times using 'Like' to compare 

Console, after the third run: 
Time spent via ODBC(milliseconds) using '=' to compare - 4,0005 
Time spent via ODBC(milliseconds) using 'Like' to compare - 3,0004 
Time spent via OLEDB(milliseconds) using '=' to compare - 1449,184 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 1451,1843 
ODBC is faster than OLEDB 362 times using '=' to compare 
ODBC is faster than OLEDB 362 times using 'Like' to compare 

Console, after the fourth run: 
Time spent via ODBC(milliseconds) using '=' to compare - 3,5004 
Time spent via ODBC(milliseconds) using 'Like' to compare - 4,5006 
Time spent via OLEDB(milliseconds) using '=' to compare - 1475,6874 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 1621,2059 
ODBC is faster than OLEDB 422 times using '=' to compare 
ODBC is faster than OLEDB 422 times using 'Like' to compare 

在此示例中的索引字段PRICE_N被包括在其中查詢的子句。 我還測試了相同的查詢,包括Where子句中的非索引字段而不是索引字段。結果是相同的〜1400 - 1600毫秒。 我的印象是,在OLEDB(VFPOLEDB)的情況下不使用索引。 我對結果不滿意,我需要使用索引。

如果有人有任何建議,我將非常感激。

+1

你見過[本條](HTTP://www.vfug。組織/通訊/ oledbproviderwaystochangesettings.htm)? – stuartd

+0

謝謝,@stuartd。我以前沒有見過,所以我已經仔細閱讀。 –

+0

謝謝@stuartd。我以前沒有見過,所以我已經仔細閱讀。我試圖使用TABLEVALIDATE = 0但無濟於事。什麼也沒有變。速度如此之低以至於很難得到讚賞。我猜測索引不被使用。但爲什麼呢?我甚至部署了一個虛擬機,在那裏安裝了所有需要的SW,但結果如下:( –

回答

0

@Sergiy, 我可以有你的解決方案:

string sqlEq = "SELECT utk_ved FROM prod WHERE Price_N = '641857'"; 
string sqlLike = "SELECT utk_ved FROM prod WHERE Price_N like '641857'"; 

TimeSpan timeSpanODBC; 
DateTime timeODBC = DateTime.Now; 

OdbcConnection odbcConnection = new OdbcConnection(@"Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=C:\Users\Vakshul\Documents\dbfs;Exclusive=No;Collate=Machine;NULL=NO;DELETED=NO;BACKGROUNDFETCH=NO;"); 
odbcConnection.Open(); 
OdbcCommand odbcCommand = new OdbcCommand(sqlEq, odbcConnection); 
odbcCommand.ExecuteScalar(); 
timeSpanODBC = DateTime.Now - timeODBC; 
double timeOdbcEqual = timeSpanODBC.TotalMilliseconds; 
System.Console.WriteLine("Time spent via ODBC(milliseconds) using '=' to compare - {0}", timeOdbcEqual.ToString()); 


timeODBC = DateTime.Now; 

odbcCommand = new OdbcCommand(sqlLike, odbcConnection); 
odbcCommand.ExecuteScalar(); 
timeSpanODBC = DateTime.Now - timeODBC; 
double timeOdbcLike = timeSpanODBC.TotalMilliseconds; 
System.Console.WriteLine("Time spent via ODBC(milliseconds) using 'Like' to compare - {0}", timeOdbcLike.ToString()); 

TimeSpan timeSpanOLEDB; 
DateTime timeOLEDB = DateTime.Now; 

OleDbConnection oleDbCon = new OleDbConnection(@"Provider=VFPOLEDB.1;Data Source=C:\Users\Vakshul\Documents\dbfs;Collating Sequence=MACHINE;Mode=Read"); 
oleDbCon.Open(); 
new OleDbCommand("set enginebehavior 80", oleDbCon).ExecuteNonQuery(); 
OleDbCommand oleDbcommand = new OleDbCommand(sqlEq, oleDbCon); 
oleDbcommand.ExecuteScalar(); 
timeSpanOLEDB = DateTime.Now - timeOLEDB; 
double timeOLEDBEqual = timeSpanOLEDB.TotalMilliseconds; 
System.Console.WriteLine("Time spent via OLEDB(milliseconds) using '=' to compare - {0}", timeOLEDBEqual.ToString()); 

timeOLEDB = DateTime.Now; 

oleDbcommand = new OleDbCommand(sqlLike, oleDbCon); 

oleDbcommand.ExecuteScalar(); 
timeSpanOLEDB = DateTime.Now - timeOLEDB; 
double timeOLEDLike = timeSpanOLEDB.TotalMilliseconds; 
System.Console.WriteLine("Time spent via OLEDB(milliseconds) using 'Like' to compare - {0}", timeOLEDLike.ToString()); 

注相同的連接在這條線

new OleDbCommand("set enginebehavior 80", oleDbCon).ExecuteNonQuery(); 

這會不會影響你的結果,但得到你想要的。除了我的頭頂,它唯一可能影響的地方是「group by」查詢。認爲你不會用舊的VFP方式通過查詢編寫組,你應該是安全的。

我的不定時 「SET ENGINEBEHAVIOR 80」:

Time spent via ODBC(milliseconds) using '=' to compare - 4.0002 
Time spent via ODBC(milliseconds) using 'Like' to compare - 1.0001 
Time spent via OLEDB(milliseconds) using '=' to compare - 352.0201 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 659.0377 

,並用 「SET ENGINEBEHAVIOR 80」:

Time spent via ODBC(milliseconds) using '=' to compare - 3.0001 
Time spent via ODBC(milliseconds) using 'Like' to compare - 2.0002 
Time spent via OLEDB(milliseconds) using '=' to compare - 15.0008 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 3.0002 
+0

再一次您是非常有幫助的確的是,使用數據引擎與Visual FoxPro 8.0的兼容性允許以避免查詢速度下降,也允許像「select t。* from(select ...)」那樣運行查詢語言爲t「,希望我能夠運行更復雜的查詢,您的幫助是非常寶貴的。 –

0

想知道...是您的「Price_n」列是NUMERIC還是STRING列。如果是數字,那麼我想知道VFP OleDb是否試圖將所有的數字轉換爲測試的STRING等價物,而不是將引用的字符串轉換爲Price_n數據類型的數字等價物,因爲我期望自然指數基於。

如果是這樣,嘗試測試和更改所有的WHERE子句分別

WHERE price_n = 641857

WHERE price_n像641857

但如果基於列的數字,那麼像真的不會適用,因爲一個號碼是一個號碼而不是像部分字符串匹配像

"1" LIKE "1" 
"1" LIKE "10" 
"1" LIKE "19302"... etc where they all start with a same value 
+0

Hi DRapp, 'price_n'是一個STRING列。這就是爲什麼Where子句中使用的引號: WHERE(price_n ='641857')。 我在這個測試中使用LIKE的原因只是一個希望,使用它可能會增加一些清晰的事情。 我應該添加我做了我的測試在Windows 7,Visual Studio 2012,.Net Framework 4.5 –

+0

@SergiyVakshul,你有PRICE_N上的索引嗎?這是可能的多鍵索引表達式中的第一列?我過去曾經使用過VFP OleDb,並且查詢速度相當快。即使在.Net 3.5和4下也是如此。儘管如此,我仍強烈建議參數化查詢。 – DRapp

+0

我的PRICE_N上有一個索引。表格中有幾個索引,其中一個索引在PRICE_N上。該索引不是多個。這只是一列的索引。至於參數化查詢,我也檢查了它 - 結果是一樣的 - 太慢了。 –

0

@Sergiy, 你在做什麼有很大的區別。 VFP6之後的版本(即2.5或2.6是包含ODBC驅動程序的最後一個軟件包)中不存在ODBC驅動程序。 IOW ODBC僅支持VFP6引擎。 OTOH VFPOLEDB支持VFP9引擎(以及所有那些添加了SQL功能的花裏胡哨的功能)。

這些引擎之間,有製作上的文本字段慢查詢的問題: 如果操作系統代碼頁是比表的代碼頁不同的搜索正在對索引其表達字符類型的完成。然後它不使用索引,而是執行表掃描。這個「bug」在VFP9的初始版本出現之後浮出水面,並沒有糾正AFAIK。

按照= vs類似,就像隱含地ANSI那樣表現得像< g>使用==操作符(完全匹配)。 With =,如果ANSI爲OFF,則將部分匹配設爲true。

PS:VFPOLEDB,即使在修正了代碼頁之後,稍微慢一點但可以忽略不計。

這裏是我的時刻與您的代碼,在測試表1,000,000行:

Time spent via ODBC(milliseconds) using '=' to compare - 41.0023 
Time spent via ODBC(milliseconds) using 'Like' to compare - 0 
Time spent via OLEDB(milliseconds) using '=' to compare - 68.0038 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 2.0002 
ODBC is faster than OLEDB 2 times using '=' to compare 
ODBC is faster than OLEDB 2 times using 'Like' to compare 

這些都是第二次運行後的時序:

Time spent via ODBC(milliseconds) using '=' to compare - 1 
Time spent via ODBC(milliseconds) using 'Like' to compare - 1.0001 
Time spent via OLEDB(milliseconds) using '=' to compare - 3.0001 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 0 
ODBC is faster than OLEDB 3 times using '=' to compare 
ODBC is faster than OLEDB 3 times using 'Like' to compare 
0

@Cetin Basoz,

在這些引擎之間,在 文本字段中存在使查詢變慢的問題:如果操作系統代碼頁是不同的租金比表的代碼頁和 搜索正在對其表達字符爲 類型的索引進行搜索。然後它不使用索引,而是執行表掃描。這個「bug」 在VFP9的初始版本之後浮出水面,而沒有糾正AFAIK。

你碰到問題的癥結所在!

我不知道這個特點。我決定檢查是否真的如此。如果你的假設是正確的,低速的原因是DBF文件和我的操作系統的代碼頁是不同的。爲了測試我安裝了Visual Fox Pro 9(我從來沒有處理過它)並將所有數據傳輸到一個新表中。然後我在Table Designer中打開了表格,並在PRICE_N字段上創建了一個常規索引。因此新表和我的操作系統的代碼頁變得相同。

然後我再次運行測試。結果發生了巨大變化。

在第一次運行後:

Time spent via ODBC(milliseconds) using '=' to compare - 12,5016 
Time spent via ODBC(milliseconds) using 'Like' to compare - 3,5005 
Time spent via OLEDB(milliseconds) using '=' to compare - 20,0025 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 3,0004 
ODBC is faster than OLEDB 2 times using '=' to compare 
ODBC is faster than OLEDB 2 times using 'Like' to compare 

第二次運行後:

Time spent via ODBC(milliseconds) using '=' to compare - 3,0004 
Time spent via ODBC(milliseconds) using 'Like' to compare - 2,5003 
Time spent via OLEDB(milliseconds) using '=' to compare - 11,0014 
Time spent via OLEDB(milliseconds) using 'Like' to compare - 3,5005 
ODBC is faster than OLEDB 4 times using '=' to compare 
ODBC is faster than OLEDB 4 times using 'Like' to compare 

謝謝,切廷Basoz。評論是真棒:)

即使我不允許更改生產DBF文件的代碼頁,至少現在我可以擺脫負擔,當我知道發生了什麼。