ADO 速度太慢

Arlung1 2004-03-19 04:16:00
各位,請問有沒有遇到adoQuery.SQL.Open執行時間太長的問題。

詳情:
1. 數據庫informix
2. Connection已經設定了CommandTimeOut時間不超過20秒
3. SQL語句用其他工具(WinSQL)執行不超過1秒鐘,但是在Delphi 7 下用adoQuery.SQL.Open 打開需要幾分鍾時間。而且CommandTimeOut失效
4. 請問如何解決?

...全文
228 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
8341 2004-03-31
  • 打赏
  • 举报
回复
ADO不好,有时候还不如ODBC来的快。我现在就用ODAC
leobearcn 2004-03-31
  • 打赏
  • 举报
回复
李维的<ado ,mts,com+ >的那本书中对ado的效率有很详细的论述,建议大家看看。
速度慢可能还可cursor location有关吧。

李惟说ado 2.5的存贮速度也就比bde慢5% 左右。然而bde现在处于维护阶段,而ado还在不断发展,以后将会更加普及吧。
Arlung1 2004-03-20
  • 打赏
  • 举报
回复
我用SQL Server、Orcale都沒問題,但是Informix就是怪。
好了,這裡寫出來,只當是朋友們遇到問題時,做個參考。

再次謝謝大家
請板主結貼
knife_s 2004-03-20
  • 打赏
  • 举报
回复
从你的解决过程来看,是你的adoquery设置有问题,不过也有点纳闷,要是真的只有十条记录

再怎么有问题也不会这么夸张吧



ujjcel 2004-03-20
  • 打赏
  • 举报
回复
如此说来是根数据库有关了,以后用到的时候注意了。
flymoon 2004-03-20
  • 打赏
  • 举报
回复
我是用SQL SERVER,也有速度慢的问题,所以
收藏&&学习
多壮志 2004-03-20
  • 打赏
  • 举报
回复
9成9是你的编码,或者某些设置有些问题。
程序用了这么多年,我还没有遇到这样的问题
quansui 2004-03-19
  • 打赏
  • 举报
回复
1.可能你的系统有问题
2.你的SQL语句可能有问题
3.你的数据表是否有主键或索引,也会提高速度的
4.你系统中的MDAC是支持ADO的数据感应软件,是不是有错误或版本低。下载个高版本的试试吧。
gwolf 2004-03-19
  • 打赏
  • 举报
回复
我是用SQL SERVER,也有速度慢的问题,所以
收藏&&学习
Arlung1 2004-03-19
  • 打赏
  • 举报
回复
更正:

//Query不用初始化,再次賦值時也不用做任何操作

改為:
//Query不用設置Connection,再次賦值時也不用做任何操作

RecordSet:=Connection.Execute('Select ...');
Query:=TADOQuery.Create(nil);
Query.RecordSet:=RecordSet;
if not Query.Eof then
...;

Arlung1 2004-03-19
  • 打赏
  • 举报
回复
續...

9. 我想了很多,最多的是 完了!完了!完了!
10.但是...
11.我吃飯時想,ADO是ActiveX導入到Delphi中來的,理論上MS ADO有的方法,Delphi也應該有。於是我回來右試了試。
12.發現了ADOConnection.Execute可以返回RecordSet。
13....
14 我試了試,速度像飛一樣。

var
Query : TADOQuery;
RecordSet : _RecordSet;
Connection: TADOConnection;

begin
//初始化Connection
Connection:=TADOConnection.Create;
Connection.ConnectionString:='...';
...

//用Connection.Execute執行SQL並返回結果集
RecordSet:=Connection.Execute('Select ...');

//將RecordSet賦值給Query.RecordSet
//Query不用初始化,再次賦值時也不用做任何操作
Query.RecordSet:=RecordSet;
if not Query.Eof then
...

謝謝大家幫忙!
Arlung1 2004-03-19
  • 打赏
  • 举报
回复
問題解決了,寫出來給大家分享:

詳情:
1. 數據庫informix
2. Connection已經設定了CommandTimeOut時間不超過20秒
3. SQL語句用其他工具(WinSQL)執行不超過1秒鐘,但是在Delphi 7 下用adoQuery.Open(之前係筆誤) 打開需要幾分鍾時間。而且CommandTimeOut失效

解決過程:
1. 我看到論壇上沒有什麽好的建議,於是我只好自己解決。首先我懷疑自己的程式造成系統内存問題(Delphi有Bug),於是我退出Delphi重新開機。
2. 打開win的工作管理員,檢測内存使用狀況。重新進入Delphi後,程式基本能運行,但是SQL執行的速度越來越慢。直到完全不動了(我寫的是Down BOM的程序,所以在遞歸中會不斷執行一些SQL)。此間,系統使用的内存的確不斷增長。
3. 聯想到我的程式中所有變量均沒有釋放内存,於是我修改了程式,加入了釋放語句。
4. 再次運行程式。出乎意料,第一個SQL語句處就已經停下來。我開始懷疑Delphi IDE對内存的管理。
5. 重新開機,再次運行。結果系統可以運行,但是效率仍然越來越低。但這次内存沒有增長。
6. 我考慮用其他的ADO類來實現功能,但是我發現其他類要不返回結果集的機制和ADOQuery一致,要不就不返回結果集。
7. 考慮到之前我試用ADOQuery.Open不能執行的情況下,ADOConnection.Execute可以執行,但是我當時沒有注意到ADOConnection.Execute有一個Overload的Funtion。
8. 我放棄了。
henreash 2004-03-19
  • 打赏
  • 举报
回复
在使用ado 的时候要小心,避免一次取大量的数据
aiirii 2004-03-19
  • 打赏
  • 举报
回复
看看 李维 的书,大多都有讲到软件调优的问题!
sixgj 2004-03-19
  • 打赏
  • 举报
回复
重来没有想你说的ADOQUERY.SQL.OPEN,一般我就是ADOQUERY.OPEN就可以了不知道你是不是写错了

重来没有想你说的ADOQUERY.SQL.OPEN,一般我就是ADOQUERY.OPEN就可以了不知道你是不是写错了

ssoj 2004-03-19
  • 打赏
  • 举报
回复
我也相信ado比dbe快,但我也相信ado的连接速度很慢!!
xthggg 2004-03-19
  • 打赏
  • 举报
回复
直接用:ADOquery.open 我没见过谁写: adoquery.sql.open的。肯定是你写的语句出问题了,ado的执行速度应该比bde快的多。
maimaizhi 2004-03-19
  • 打赏
  • 举报
回复
你保时数据库一直连接住
leobearcn 2004-03-19
  • 打赏
  • 举报
回复
不至于啊,照例说bde没有ado连接速度快啊。 呵呵
dance_code 2004-03-19
  • 打赏
  • 举报
回复
是不是ADO对你的数据库支持不好啊,也说不定,没用过infomix
加载更多回复(4)
原文地址:https://github.com/andolove/Data 感谢作者!很实用 简单的Ado.net数据访问客户端。 数据库访问入口 获取IDbClient 在开始之前,先添加一个数据库访问入口。当然,也可以使用任何你喜欢的方式来创建IDbClient(的实现类)实例。 public static class Db { private static readonly Dictionary KnownClients = new Dictionary(); public static IDbClient Northwind { get { return GetClient("Northwind", "server=.;database=Northwind;trusted_connection=true;"); } } private static IDbClient GetClient(string name, string connectionString) { IDbClient client; if (KnownClients.TryGetValue(name, out client)) return client; lock (KnownClients) { if (KnownClients.TryGetValue(name, out client)) return client; // 创建IDbClient的实例 client = new SqlDbClient(connectionString); KnownClients.Add(name, client); } return client; } } 现在,可以使用Db.Northwind来访问SQLServer的Northwind示例数据库了。 访问其他数据库 如果要访问MySql,可以用几行代码实现一个面向MySql的IDbClient实现。下面以使用 MySql.Data.dll 作为MySql .net客户端提供器为例。 /// /// Mysql数据库访问客户端。 /// public class MysqlDbClient : AbstractDbClient { private readonly string _connectionString; /// /// 使用指定的数据库类型和连接字符串初始化的新实例。 /// /// 连接字符串。 public MysqlDbClient(string connectionString) { ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, "connectionString"); _connectionString = connectionString; } /// /// 获取当前实例所使用的数据库连接字符串。 /// public override string ConnectionString { get { return _connectionString; } } /// /// 获取当前实例所使用的实例。 /// protected override DbProviderFactory Factory { get { return MySql.Data.MySqlClient.MySqlClientFactory.Instance; } } } 现在可以创建MySql的访问客户端了: IDbClient client = new MysqlDbClient("server=.;database=MySqlDb;uid=user;pwd=password"); 类似的,可以创建访问Oracle,Sqlite或是其他数据库的客户端,只需要找到对应的DbProviderFactory实例即可。 基本数据库操作 基础CRUD // 查询 string productName = (string)Db.Northwind.Scalar( "SELECT ProductName FROM Products WHERE ProductID=115"); DataTable productTable = Db.Northwind.DataTable("SELECT * FROM Products"); // 更新 int affectedRows = Db.Northwind.Execute( "UPDATE Products SET ProductName='The Name' WHERE ProductID=115"); // 在没有命中一行的时候抛出异常 int expectedSize = 1; Db.Northwind.SizedExecute( expectedSize, "UPDATE Products SET ProductName='The Name' WHERE ProductID=115"); // 获取一行 IDataRecord record = Db.Northwind.GetRow( "SELECT ProductName, SupplierID FROM Products WHERE ProductID=115"); int supplierId = Convert.ToInt32(record["SupplierID"]); // 在不用在意资源释放的情况下使用DataReader,利用了foreach的机制,在循环结束后DataReader会自动关闭 IEnumerable rows = Db.Northwind.Rows( "SELECT ProductName, SupplierID FROM Products WHERE ProductID=115"); foreach (IDataRecord row in rows) { Console.WriteLine(row["ProductName"]); } 使用参数和调用存储过程 // 使用参数 DbParameter parameter = Db.Northwind.CreateParameter(); parameter.DbType = DbType.String; parameter.ParameterName = "CustomerID"; parameter.Value = "ALFKI"; parameter.Direction = ParameterDirection.Input; // 调用存储过程 CustOrderHist @CustomerID DataSet ds = Db.Northwind.DataSet( "CustOrderHist", new[] { parameter }, CommandType.StoredProcedure); // 使用DbClientParamEx中的扩展方法快速创建参数(需要using Data命名空间) DbParameter[] parameters = new[] { Db.Northwind.CreateParameter("id", DbType.Int32, 115, direction: ParameterDirection.Input), Db.Northwind.CreateParameter("name", DbType.String, "Ikura", 5) }; Db.Northwind.DataSet("SELECT * FROM Products WHERE ProductName=@name OR ProductID=@id", parameters); 使用Mapper IMapper接口定义了从IDataRecord到T类型的映射,可以用过实现该接口,以便从数据库读取并创建特定类型实例及实例的集合。 public class Product { public int ProductID; public string ProductName; } public class ProductMapper : IMapper { public Product MapRow(IDataRecord record, int rowNum) { var product = new Product(); product.ProductID = Convert.ToInt32(record["ProductID"]); product.ProductName = record["ProductName"].ToString(); return product; } } 利用上面的ProductMapper,我们可以直接从查询中创建Product实例了。 // 获取一个实例 Product product = Db.Northwind.Get( new ProductMapper(), "SELECT * FROM Products WHERE ProductID=115"); // 获取实例的集合 IList products = Db.Northwind.List(new ProductMapper(), "SELECT * FROM Products"); Mappers类中已经定义了部分简单类型的Mapper实现,以便实现便捷的查询。 // 使用已定义好的简单Mapper IList productNames = Db.Northwind.List( Mappers.String(), "SELECT ProductName FROM Products"); IList productIds = Db.Northwind.List( Mappers.Int32(), "SELECT ProductID FROM Products"); // 使用实现IConvertible的类型创建Mapper IList orderDates = Db.Northwind.List( Mappers.Convertible(), "SELECT OrderDate FROM Orders"); 使用事务 使用CreateTransaction方法来获取一个ITransactionKeeper事务容器。获取到的事务容器自身也实现了IDbClient,可以在其上进行各种CRUD操作。 事务的最后,别忘了Commit。 ITransactionKeeper同时也实现了IDisposable接口,其Dispose方法能够在事务没有提交时进行事务回滚(如果已经提交,则什么也不做),利用这个机制和C#的using语法,可以很方便的编写一个在出现异常时回滚的事务操作。 using (ITransactionKeeper tran = Db.Northwind.CreateTransaction()) { tran.Execute("UPDATE Products SET ProductName='The Name' WHERE ProductID=115"); tran.Execute("UPDATE Products SET ProductName='The Name2' WHERE ProductID=118"); tran.Commit(); } Dynamic扩展 在Data.Dynamic命名空间的ObjectiveExtension类中,定义了一套IDbClient的扩展方法,能够使用更快捷的方式进行数据库操作。 .net对象传参 这些扩展方法具有与IDbClient中的方法很类似的签名,但能够接收一个用于存放参数信息的.net对象,以节省许多编码量(是的,和Dapper、ServiceStack.OrmLite很相似)。 通过这些扩展方法,上面使用参数的示例可以这样写了: DataSet ds = Db.Northwind.DataSet( "CustOrderHist", new { CustomerID = "ALFKI" }, CommandType.StoredProcedure); DataTable dt = Db.Northwind.DataTable( "SELECT * FROM Products WHERE ProductName=@name OR ProductID=@id", new { name = "Ikura", id = 115 }); 获取类型实例 现在不指定Mapper就可以直接进行对象查询了。 Product product = Db.Northwind.Get("SELECT * FROM Products WHERE ProductID=115"); IList products = Db.Northwind.List("SELECT * FROM Products"); IList orderDates = Db.Northwind.List("SELECT OrderDate FROM Orders"); 在这些方法内部,会在运行时动态生成对应的Mapper,并且生成一次以后,信息会被缓存下来,不需要每次都重新创建。当然,因为做了更多的是事情,它还是会比非扩展的原生版本慢那么一点点。 也可以使用匿名对象作为实体模板,在许多场景尤其是处理包含少量字段(但又多于1个)时尤其方便。 var template = new { ProductID = 0, ProductName = string.Empty }; var productsByTemplate = Db.Northwind.TemplateList(template, "SELECT * FROM Products"); 关于字段名称的匹配 .net对象的属性和公共字段使用Pascal命名法,但数据库规范中的字段命名法可能不一样,比如MySql的snake_case命名法;而且也有太多的数据库设计使用“意识流”了。为了解决这个命名差异问题,查询结果映射到非匿名对象字段时支持字段名称的模糊匹配,具体规则如下,越靠前的规则优先级越高: 查询结果的字段名称和对象字段名称完全一致; 大小写不敏感的匹配;例:查询结果字段goodName可映射到对象字段GoodName。 查询结果的字段名称移除下划线(头尾的下划线将保留)之后,再进行大小写不敏感的匹配;例:查询结果字段good_name可映射到对象字段GoodName;_goodName不会映射到GoodName,因为头尾的下划线不会被忽略。 字体匹配时,考前的规则将优先进行匹配,没有匹配到的字段再使用下一优先级的规则进行匹配。若所有规则都为命中,则对象字段将在映射中被忽略从而保持字段类型的默认值。 注意:使用匿名对象作为模板查询时,匿名对象的字段名称需和查询结果的字段名称完全匹配,不支持模糊匹配。 Indexing扩展 在Data.Indexing命名空间的IndexingExtension类中,定义了另外一套IDbClient的扩展方法,能够基于索引访问传入的参数。 记得string.Format方法吗: string.Format("My name is {0}, I'm {1} years old.", "John Doe", 8); 类似的,这些扩展方法用起来是这个样子的: DataTable dt = Db.Northwind.DataTable( "SELECT * FROM Products WHERE ProductName=@0 OR ProductID=@1", "Ikura", 115); IList products = Db.Northwind.List( "SELECT * FROM Products WHERE ProductID IN (@0, @1)", 15, 16); 通常在一个地方并不混用两套扩展。Dynamic扩展会更泛用一些,但在一些特定的场景下,使用Indexing扩展也是个好主意。还有,这套扩展方法速度会更快一些。
2.5主要变动: 1.重要改进:新版本中Delphi下的VCL控件已经比较完善,封装良好,与Delphi无缝连接,改变了旧版中需要将Dataset中的数据复制到报表引擎中的实现方式,通过模拟ADO接口的方式直接支持BDE/ClientDataset/等非ADO方式的Dataset,不需要考虑太多的COM方面的因素,强烈建议Delphi的开发者直接使用该VCL控件。 使用VCL控件编译的程序发布时,将AcReport.dll和您的EXE放在同一个文件夹下一起发布即可,不需要运行RegSvr32来注册控件,VCL中的代码会自动注册该控件。 2.完善文本控制方式(在设计器界面上增加了此项菜单): 1).当文本控制设置为自动适应单元格(自动缩放字体)时,选择上对齐方式时,也能自动换行。 2)当文本控制设置为截断字符时,支持自动换行,保持单元格的高度不变,在某些特殊应用中,不管文本如何变化,可以保持表格的形状不变。 3.增加了OnSaveReport事件,当用户在设计器中点击“保存”按扭时,会触发此事件,程序可以响应此事件执行自定义保存,例如可以将报表保存到数据库中,或者返回一个信息给设计器用户。 4.直接支持ADO.net中的Dataset和DataTable对象,不需要再通过CustDataBuiler对象来转换,大大提高了在.net下的运行速度。(需要引用 AcNetUtils.dll,具体使用方法请参考Demo) 代码示例: //Dataset: //2.5以前的版本需要将Ado.net下datatable在AC中copy一个复本,速度比较慢 // AcReport.AcUtils.CopyDatasetToAcRptEngine(mDataset, mac, false); //新版本的处理方式,通过ADO-ADO.net适配器的方式直接访问 DbAdapter.FillDatasetToAC(mDataset, mac); //DataTable: mDataset.Tables["zlemployee"].TableName = "雇员档案"; AcReport.AcUtils.CopyTableToAcRptEngine(mDataset.Tables["雇员档案"], mac, false); //重新加入一个表到AcReport (旧版本方式) //在2.5以后的版本中,可以用如下的方式将ADO.net的DataTable对象通过AcRecordsetAdapter转换为ADO接口的方式直接加入到AcEngine, //这样做就不需要在AC中复制一个复本,大大提高的速度。 AcRecordsetAdapter RecordAdp = new AcRecordsetAdapter(mDataset.Tables["雇员档案"]); mac.AddNetAdoData("雇员档案", RecordAdp); // 以上两行也可以直接调用 AcNetUtils 类库里提供的现成方法(效果是一样的): AcNetUtils.DbAdapter.FillDataTableToAC(mDataset.Tables["雇员档案"], mac); 5.可拖动对象设计功能增强 6.支持 条码 Code128 Auto ACReport简介 Anycell Report(简称AC Report)是一款中国式报表组件,是国内最早的基于表格,支持图文混排、公式和脚本的中国式报表工具之一。就如Anycell Report的名称那样,灵活强大的表格功能一直是AC Report区别于其它软件或控件最显著的特征之一,AC Report 表格取消了传统表格概念中“列”的概念,每一行上的单元格数量可以不等,且可以自由活动,勿须上下对齐,在制作复杂的中国式报表时可以避免很多不必要的合并拆分操作,制作表格更加方便和随心所欲,并且省时省力。AC Report单元格支持多种丰富的形态,例如格式化文本、图片、图表、条码、OLE容器等。 AC Report的一些基本特点: 1.独具特色的表格,风格与Word表格相似,但可以做出比Word或Excel更灵活的表格来。 2. 功能全面、专业的中国式报表设计器,中国用户更易于学习和接受。 3.支持多种单元格样式,可以打印图像、图表(直方图、折线图等)、Rich文本、 条形码、中式财务帐薄、支持在报表中嵌入Word、Excel文档等。 4. 强大的计算和合计功能。内置表达式解析系统和函数库。 5. 可扩充性,可以在应用程序中给报表引擎扩充函数库、报表样式和单元格样式。 6.支持多种报表样式,如清单式、分组、交叉表、以及子报表

2,498

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 数据库相关
社区管理员
  • 数据库相关社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧