C# 使用OLEDB(VFPOLEDB)对DBF文件运行查询太慢
我正在开发一个界面,用于在WinForm应用程序中显示DBF文件中的数据。 我开始使用OdbcConnection。尽管它工作正常,但由于不支持Visual FoxPro驱动程序子查询的某些限制,我打开了OLEDBVFPOLEDB。现在,我能够运行复杂的查询,但出现了新的困难,必须加以解决。问题是这些查询太慢。比预期慢100倍 下面是演示的代码。 有一个DBF表“PROD”。索引字段PRICE\N用于查询的Where子句中。该表位于运行应用程序的同一台PC上。正如您所看到的,通过ODBCMicrosoft Visual FoxPro驱动程序和OLEDBVFPOLEDB运行查询所花费的时间差别很大C# 使用OLEDB(VFPOLEDB)对DBF文件运行查询太慢,c#,visual-foxpro,C#,Visual Foxpro,我正在开发一个界面,用于在WinForm应用程序中显示DBF文件中的数据。 我开始使用OdbcConnection。尽管它工作正常,但由于不支持Visual FoxPro驱动程序子查询的某些限制,我打开了OLEDBVFPOLEDB。现在,我能够运行复杂的查询,但出现了新的困难,必须加以解决。问题是这些查询太慢。比预期慢100倍 下面是演示的代码。 有一个DBF表“PROD”。索引字段PRICE\N用于查询的Where子句中。该表位于运行应用程序的同一台PC上。正如您所看到的,通过ODBCMicr
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
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
在此示例中,查询的Where子句中包含一个索引字段PRICE\N。
我还测试了相同的查询,在Where子句中包含非索引字段,而不是索引字段。结果是相同的~1400–1600毫秒。
我的印象是,在OLEDBVFPOLEDB的情况下,不使用索引。
我对结果不满意,我需要使用索引
如果有人有任何建议,我将非常感激。只是想知道。。。价格列是数字列还是字符串列。如果是数字,那么我想知道VFP OleDb是否正在尝试将您的所有数字转换为用于测试的等效字符串,而不是将引用的字符串转换为价格数据类型的等效数字,正如我预期的自然指数所基于的那样 如果是这样,请尝试测试并将所有WHERE子句分别更改为 其中价格=641857 哪里的价格像641857 但是如果是基于数字的列,那么Like实际上不适用,因为数字是数字,而不像部分字符串匹配
"1" LIKE "1"
"1" LIKE "10"
"1" LIKE "19302"... etc where they all start with a same value
@塞吉伊,
你在做什么有很大的不同。VFP6之后的版本(即2.5或2.6是包含ODBC驱动程序的最后一个包)不存在ODBC驱动程序。IOW ODBC仅支持VFP6引擎。OtohVFPoleDB支持VFP9引擎和所有添加的SQL功能
在这些引擎之间,有一个问题使得文本字段的查询速度变慢:
如果OS代码页与表的代码页不同,并且搜索是在表达式为字符类型的索引上进行的。然后它不使用索引,而是进行表扫描。这个错误在VFP9的初始发布后出现,并没有在AFAIK中纠正
根据=vs like,like隐式地表示ANSI,因此使用==运算符精确匹配,其行为类似于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
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
@塞廷·巴索兹
在这些引擎之间,有一个问题使得查询速度变慢
文本字段:如果OS代码页与表的代码页不同,则
正在对表达式为字符的索引执行搜索
类型然后它不使用索引,而是进行表扫描。这个虫子
在VFP9首次发布后浮出水面,未经AFAIK纠正
你抓住了问题的关键
我不知道那个怪癖。我决定看看是否真的是这样。如果您的假设是正确的,那么低速的原因是DBF文件和我的操作系统的代码页不同。为了测试我是否安装了Visual Fox Pro 9I,我以前从未处理过它,并将所有数据传输到一个新表中。然后我在表设计器中打开表,并在PRICE\N字段上创建了一个常规索引。因此,新表和我的操作系统的代码页变得相同
然后我再次运行测试。结果发生了巨大的变化
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
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 - 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
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
谢谢,塞廷·巴索兹。评论非常棒:
即使不允许我更改生产DBF文件的代码页,但至少现在当我知道发生了什么时,我可以轻松地摆脱负担。@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());
注意同一连接上的这一行:
这不会影响你的结果,但会得到你想要的。在我脑海中,它可能影响的唯一地方是分组查询。认为您不会以旧的buggy VFP方式编写分组查询,您应该是安全的
我在没有设置EngineBhavior 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
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
以及设置EngineBhavior 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
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
你看到了吗?谢谢,斯图亚特。我以前没看过,所以我读得很透彻。谢谢,@stuartd。我以前没看过,所以我读得很透彻。我尝试使用TABLEVALIDATE=0,但没有效果。一切都没有改变。速度太慢,很难生活。我猜是a
你不用。但为什么呢?我甚至部署了一个虚拟机,在那里安装了所有需要的软件,但结果是一样的:那么在列上定义了CDX索引?你看到了吗?另外,你说你正在使用VFPOLEDB驱动程序,因为本地驱动程序不支持子查询:我记得这是我在VFP开发时的一个痛点,那是在当年的数字中有很多“9”的时候,尽管这是一个痛点,但可以通过创造性地使用外部联接来解决。你真的需要子查询吗?我用VisualFoxPro重新标记了你的问题,希望你能从仍然使用iTiDrapp的人那里得到帮助,“price\n”是一个字符串列。这就是Where子句中使用引号的原因:Where price_n='641857'。我在这个测试中使用LIKE的原因仅仅是希望使用它可以增加对正在发生的事情的了解。我应该补充一下,我在Windows7、VisualStudio2012、.NETFramework 4上进行了测试。5@SergiyVakshul,你们有价格指数吗?这是可能的多键索引表达式中的第一列?我过去使用过VFP OleDb,查询速度非常快。。即使是在.NET3.5和.NET4下。但对于生产,我强烈建议将查询参数化。我有一个关于价格的索引。表中有几个索引,其中一个是关于价格的。这个索引不是多个。它只是一列的索引。至于参数化查询,我也检查了它——结果是一样的——太慢了。@SergiyVakshul,最后一个想法。。。数据库是静态的吗?即:不更改内容和固定数据,这些数据不会被基于web的内容读取/写入,但可能通过其他方式填充。。。如果是这样,并且您将表/cdx文件作为基于web的/C查询的只读权限,则O/S不需要对任何可能的锁定执行任何开销,即使它只是以任何方式进行查询。还有,表格有多大?比如10是假的,不是吗?LIKE是隐式启用的,其行为就像您使用了==。同样,您非常有帮助。事实上,使用与VisualFoxpro8.0兼容的数据引擎可以避免查询速度的降低。它还允许从select运行查询,如select t.*。。。作为t。希望我能够运行更复杂的查询。你的帮助真是无价之宝。