`
laorer
  • 浏览: 435734 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

<转>关系数据库性能问题

    博客分类:
  • j2EE
阅读更多
2005-01-21
    
缩略显示    
关键字: 企业应用       
http://buaawhl.iteye.com/category/?category=5350

关系数据库性能问题

一、任务描述

工作中的一个数据批量任务,涉及到4张基本表和4张业务数据表。
基本表 (Basic Table) 数据量不大,每个表最多几百条记录;业务表 (Transaction Table) 数据量较大,每个表有几十万条记录。

以前的版本使用OO(O/R ?)方式,
(1) SQL查询数据库选出一个业务表的数据,每条记录映射为一个Object。
(2) 循环每个Object,根据属性 查询数据库,取出关联的表数据,映射为Object;依此类推,一步步取出相关数据Object。然后计算并生成结果数据。

这种方案,第一次取出的数据集很大,循环步数很多,而且每一步里面都要涉及到多次数据库查询,速度很慢,处理一个月的上万条数据,都需要几个小时。类似于

代码
  1. Select * from Transact_A where ….   
  2. While(rs.next()){   
  3. a.populate(rs);   
  4.   
  5. If(a…) {   
  6.    Select * from Transact_B where ….   
  7.    If( … ) select * from Basic_B where ….   
  8. }else{   
  9.    Select * from Basic_A where ……   
  10. }   
  11. ….   
  12. }   
<script>render_code();</script>

 

后续版本,我决定采用 Join Table的方式来处理,试图用一个复杂的Big Join Query / View 一次把所有的相关数据记录全都取出来。整个处理过程中,只需要一次数据库查询。

 

代码
  1. Select * from (Transact_A left join Basic_B on ….) inner join Transact_B on .., C, D, E… Where … <  …. > … not exists… a lot of conditions.   
  2.   
  3. While(rs.next()){   
  4. a.populate(rs);   
  5. b.populate(rs);   
  6.   
  7. if(a… b.. ) …   
  8. …   
  9. }   
<script>render_code();</script>

 

一部分 Business Logic (条件比较等)移动到SQL里面,代码的可读性变差,运行速度提高。
由于业务逻辑的复杂性,一条SQL很难恰好选出需要处理的数据,为了最大限度的减少不必要的数据,有些比较大的复合View还被多次引用。
几千条数据,这条SQL工作还好,几秒钟、十几秒钟就返回结果集;几万条数据,这条SQL需要几分钟才能够返回;几十万条数据,运气好,10多分钟、几十分钟返回,运气不好,就干脆不返回了。

二 SQL Optimization
Oracle网站有Performance Tuning的PDF文档,详细介绍了语句置换,hint, index, explain plan, SQL Trace等方法。
这里有一篇比较全的翻译的SQL调优文章,
http://www.chinaunix.net/jh/19/214182.html

其中的第15条明确说明,SQL中的 = 操作符 支持 Tuple元组操作,这个 = 可以用来给一个元组Tuple赋值,也可以比较两个元组Tuple。

代码
  1. 15. 减少对表的查询    
  2. 在含有子查询的SQL语句中,要特别注意减少对表的查询.    
  3.   例如:     
  4.      Slow:   
  5.           SELECT TAB_NAME    
  6.           FROM TABLES    
  7.           WHERE TAB_NAME = ( SELECT TAB_NAME     
  8.                                 FROM TAB_COLUMNS    
  9.                                 WHERE VERSION = 604)    
  10.           AND DB_VER= ( SELECT DB_VER     
  11.                            FROM TAB_COLUMNS    
  12.                            WHERE VERSION = 604)    
  13.   
  14.      Fast:   
  15.           SELECT TAB_NAME    
  16.           FROM TABLES    
  17.           WHERE  (TAB_NAME,DB_VER)    
  18.                = ( SELECT TAB_NAME,DB_VER)     
  19.                    FROM TAB_COLUMNS    
  20.                    WHERE VERSION = 604)    
  21.   
  22.      Update 多个Column 例子:    
  23.      Slow   
  24.            UPDATE EMP    
  25.            SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES),    
  26.               SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES)    
  27.            WHERE EMP_DEPT = 0020;    
  28.   
  29.      Fast   
  30.            UPDATE EMP    
  31.            SET (EMP_CAT, SAL_RANGE)    
  32.  = (SELECT MAX(CATEGORY) , MAX(SAL_RANGE)    
  33.  FROM EMP_CATEGORIES)    
  34.            WHERE EMP_DEPT = 0020;   
<script>render_code();</script>

 

其中的第8条,我恰好用得上。

代码
  1. 8. 使用DECODE函数来减少处理时间    
  2. 使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.    
  3. 例如:    
  4.    SELECT COUNT(*),SUM(SAL)    
  5.    FROM EMP    
  6.    WHERE DEPT_NO = 0020    
  7.    AND ENAME LIKE ‘SMITH%’;    
  8.    SELECT COUNT(*),SUM(SAL)    
  9.    FROM EMP    
  10.    WHERE DEPT_NO = 0030    
  11.    AND ENAME LIKE ‘SMITH%’;    
  12. 你可以用DECODE函数高效地得到相同结果    
  13. SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,    
  14.         COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,    
  15.         SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,    
  16.         SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL    
  17. FROM EMP WHERE ENAME LIKE ‘SMITH%’;    
  18. 类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.   
<script>render_code();</script>

 

正好用来更新 parent 纪录中关于 child的统计字段。以前我这么写,

代码
  1. update parent p   
  2. set    
  3. balance_1 = (select sum(amount) from child c where  c.parent_id = p.id and type in (12))    
  4. balance_2 = (select sum(amount) from child c where  c.parent_id = p.id and type in (34))   
  5. where …   
<script>render_code();</script>

 

现在我这么写,

代码
  1. update parent p   
  2. set    
  3. (balance_1, balance_2) = (   
  4. select    
  5. sum(decode(type, 1, amount, 2, amount, null)) as balance_1,   
  6. sum(decode(type, 3, amount, 4, amount, null)) as balance_2,   
  7. from child c where  c.parent_id = p.id)    
  8. where …   
<script>render_code();</script>

 

三 临时表
优化了半天,瓶颈在于对其中一个Big View的多次使用上。只好用空间换时间,把这个多次使用的View先放到临时表里面。
业务逻辑有这样的匹配逻辑,选择最符合条件的数据,其他的数据不用。

代码
  1. Select * from   
  2. (Select * from temp    
  3. where …   
  4. order by column_1, column_2, column_3) t   
  5. where t.rownum = 1  -- 只选择排在最前面的一条   
<script>render_code();</script>

 

如果直接用上面这段SQL来过滤temp数据,比较麻烦。我干脆又在temp里面多加了一个额外字段match_level, 专门用来存放匹配级别。
创建临时表数据的时候,直接生成这个match_level。

代码
  1. Insert into temp   
  2. select    
  3. big_view.*,   
  4. decode(column_1,  … ) || decode(column_2, …) || decode(column_3, …) as match_level   
  5. from big_view where …   
<script>render_code();</script>

 

这里把多个column排序结果综合到一个字段里面,便于后面的比较。
于是,我就可以用一条相对比较简单的SQL删除掉 不是最佳匹配的纪录。

代码
  1. delete temp   
  2. where exists(   
  3. select * from   
  4. (select id, max(match_level) from temp t group by id having count(*) > 1)  t   
  5. where temp.id = t.id and temp.match_level < t.match_level)   
<script>render_code();</script>

 

处理一个月的数据,上万条记录的情况下,上面这两条insert和 delete执行时间加起来在10 -- 20秒左右。后面的一个Big Query就可以用这个temp table直接把恰好要使用的数据取出来,10秒左右就可以返回结果集(几万条)。处理这个结果集的时间,几分钟左右。
处理24个月的几十万条数据,需要几十分钟。速度提高了几十倍。

既然为了速度,用了这么多vendor native SQL feature, Big Join, temp table, 已经没有移植性可言,为什么不干脆用PL/SQL?
我对PL/SQL语法不熟悉,只是尽量把条件判断过滤放到SQL里面,而重要的计算公式部分(还是比较复杂的)在Java里面处理。我觉得,SQL即使带一点Native feature,也应该比Stored Procedure容易移植。

四 对象数据库

关系数据库号称 更快,支持更复杂的数据类型和关系,数据间的关联查询更快。

不算那些Java, C++等Object的存储工具,只算那些称得上DB的,开源的Object Database有db4object, OZONE, GigaBase(Object Relational Database)等。
(Berkeley DB勉强算得上Object Database?)
存储空间和性能还无法和商业数据库比。不像关系数据库,有了MaxDB, Ingres, PostgreSQL等比较成熟的开源关系数据库。
商业对象数据库挺多,这里就不罗列了。我看的资料比较的多的是Objectivity/DB和Intersystems Cache’。
http://www.objectivity.com
http://www.intersystems.cn
http://www.intersystems.com

两者都号称大数据量、高并发、高性能。通过看过的文档和资料,我更看好Cache’一些。似乎Cache’ 更快,更便宜,支持关系模型更好。Cache’号称 后关系数据库 Post Relational Database。当然,Objectivity是purer Object Database,面向对象特性也许更多一些。

关于对象数据库性能,有两种相反的说法。

1. 对象数据库 比 关系数据库 快

引用

原文
http://www.cnblogs.com/xgchang/archive/2004/12/05/26474.html
⑷性能的比较
ODBMS和RDBMS产品数据存取性能的差别已按通用测试标准验证过了。SUN公司的Riok Cattell等人著的“对象数据库评估”(1991年对象世界会议文集)已对四个ODBMS产品:Objectivity,Objectstore,Ontos,Versant以及两个RDBMS产品:Sybase和Ingress进行了测试。一般说来,对于“冷”数据存取(对磁盘数据库存取)ODBMS比RDBMS平均快5倍;对于“热”数据存取(在内存中的数据库存取)要快30倍,对于“热导航”(在内存中对某一给定的对象访问与之相联系的所有对象)ODBMS任何一个产品都比RDBMS的每一个产品性能要高出三个数量级。

 

Objectivity/DB自己的Bench Mark文章这样写,在小数据量下,RDBMS(Oracle)更快,数据量越大,Objectivity就会比RDBMS快的越多。

2. 对象数据库 比 关系数据库 慢

引用

原文
http://www.fic.se/MScThesis.Frost.Beta.pdf

Multi-dimensional and relational data warehouses have problems.
expressing complex data types. Object orientation on the other hand deal with complex
data types but lacks in performance on the database technology side.

object-oriented database management systems (OODBMS) the poor performance on ad- hoc queries.

object-oriented data warehouse still face the problem of ad-hoc query performance on large datasets, a problem which multi-dimensional, relational and hybrid techniques overcomes.

 

 

原文
http://www.intersystems.co.jp/forum2004/pdf/cache.pdf

从这张图可以看出,Objectivity比关系数据库慢,Cache’比关系数据库快。

DBPerformance.JPG
 描述:  
 文件大小:  59 KB
 看过的:  文件被下载或查看 421 次

DBPerformance.JPG
下载
分享到:
评论

相关推荐

    C#+List+GridControl实现主从表嵌套

    本篇将深入探讨如何利用`C#`中的`List&lt;T&gt;`集合类以及DevExpress的`GridControl`控件实现主从表的嵌套显示,这在数据库操作和数据可视化中非常常见。 `List&lt;T&gt;`是.NET Framework中`System.Collections.Generic`命名...

    Java数据编程指南

    附录&lt;br&gt;附录A SQL入门&lt;br&gt;什么是SQL&lt;br&gt;什么是数据库&lt;br&gt;关系数据库基础&lt;br&gt;关系数据库的优点和缺点&lt;br&gt;SQL:数据定义&lt;br&gt;基本数据操作&lt;br&gt;数据完整性&lt;br&gt;表达式&lt;br&gt;连接&lt;br&gt;合并&lt;br&gt;子查询&lt;br&gt;小结&lt;br&gt;附录B 序列...

    AppFramework数据库访问组件_代码生成插件_V1.1.rar

    &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;下面三张表格罗列的测试数据,可以明显看出AppFramework数据库访问组件的性能全面超越了IBatisNet: &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;表I –10并发20循环(数据库和测试机分开)&lt;br&gt;&lt;br&gt;对比项目&lt;br&gt;iBatis2.0&lt;br&gt;...

    AppFramework_V1.0

    720&lt;br&gt; 1.59&lt;br&gt;&lt;br&gt;1.53&lt;br&gt; &lt;br&gt;&lt;br&gt; &lt;br&gt;&lt;br&gt;表II –50并发4循环(数据库和测试机分开)&lt;br&gt;&lt;br&gt;对比项目&lt;br&gt; iBatis2.0&lt;br&gt;&lt;br&gt;(毫秒)&lt;br&gt; AppFramework&lt;br&gt;&lt;br&gt;(毫秒)&lt;br&gt; 后者前者性能对比&lt;br&gt;&lt;br&gt;(倍)...

    AppFramework_V1.0_New

    &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;下面三张表格罗列的测试数据,可以明显看出AppFramework数据库访问组件的性能全面超越了IBatisNet: &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;表I –10并发20循环(数据库和测试机分开)&lt;br&gt;&lt;br&gt;对比项目&lt;br&gt;iBatis2.0&lt;br&gt;...

    mysql5.1中文手册

    控制查询优化器的性能&lt;br&gt;7.5.4. 编译和链接怎样影响MySQL的速度&lt;br&gt;7.5.5. MySQL如何使用内存&lt;br&gt;7.5.6. MySQL如何使用DNS&lt;br&gt;7.6. 磁盘事宜&lt;br&gt;7.6.1. 使用符号链接&lt;br&gt;8. 客户端和实用工具程序&lt;br&gt;8.1. 客户端...

    TCP-IP技术大全

    TCP/IP和Internet 8&lt;br&gt;2.1 一段历史 8&lt;br&gt;2.1.1 ARPANET 8&lt;br&gt;2.1.2 TCP/IP 9&lt;br&gt;2.1.3 国家科学基金会(NSF) 9&lt;br&gt;2.1.4 当今的Internet 12&lt;br&gt;2.2 RFC和标准化过程 12&lt;br&gt;2.2.1 获得RFC 13&lt;br&gt;2.2.2 RFC索引 13&lt;br...

    Tomcat下配置MySQL数据库连接池

    2. **MySQL**:一款流行的关系型数据库管理系统。 3. **连接池**:通过预创建一定数量的数据库连接,并存储在一个池中供应用程序复用,从而避免频繁创建和销毁数据库连接所带来的性能开销。 #### 三、配置方法 根据...

    JDBC驱动包,Dm7JdbcDriver17.jar。

    达梦数据库管理系统(DM7)是中国自主研发的一款高性能、高可用性的关系型数据库管理系统。它支持SQL标准,具备分布式、集群、并行计算等多种架构,适用于大数据处理和高并发访问场景。DM7提供了丰富的数据库功能,...

    各种数据库连接字符串

    其中,`sambrown` 代表服务器名称,`mydatabase` 是数据库名称,`&lt;hostname&gt;` 和 `&lt;port&gt;` 表示服务器主机名和端口,`&lt;username&gt;` 和 `&lt;password&gt;` 用于用户身份验证。 #### Microsoft SQL Server Microsoft SQL ...

    javaservlet连接mysql数据库.pdf

    其次,MySQL是一个流行的关系型数据库管理系统,它使用SQL作为查询语言,提供了SQL数据库的全部功能。数据库主要用于存储、检索、操作数据。在Servlet中操作数据库,通常会使用JDBC(Java Database Connectivity)...

    Tomcat中数据库连接池的配置和使用

    &lt;value&gt;org.apache.commons.dbcp.BasicDataSourceFactory&lt;/value&gt; &lt;/parameter&gt; &lt;parameter&gt; &lt;name&gt;driverClassName&lt;/name&gt; &lt;value&gt;com.microsoft.jdbc.sqlserver.SQLServerDriver&lt;/value&gt; &lt;/parameter&gt; ...

    db2数据库常用命令汇总

    `db2 grant &lt;权限&gt; on &lt;对象&gt; to &lt;用户&gt;`:赋予用户对特定数据库对象的操作权限。 `db2 revoke &lt;权限&gt; on &lt;对象&gt; from &lt;用户&gt;`:撤销用户对数据库对象的权限。 9. **性能监控** `db2pd -db &lt;数据库名&gt; -table ...

    Object Browser7.0中文版(ORACLE数据库的开发工具)

    使用[关联信息图]可以清楚的显示数据库对象间的相互调用关系.&lt;br&gt; &nbsp;&nbsp;&nbsp;&nbsp;使用输出机能可以将数据图表通过OLE输出成Microsoft&nbsp;Excel文件.&lt;br&gt; 使用[显示SQL语法]机能可以提示您所有SQL的...

    Hibernate使用Tomcat连接池.doc

    Hibernate作为一个流行的对象关系映射(ORM)框架,能够简化数据库操作,但同时也需要数据库连接来执行SQL语句。本文将详细介绍如何在Hibernate中使用Tomcat的内置连接池DBCP(Database Connection Pool)。 首先,...

    <转>HSQLDB 安装与使用

    HSQLDB因其小巧、快速和易用性而受到广泛的欢迎,尤其适合于对数据库性能有高要求但又不希望有太多复杂性的项目。 ### 安装HSQLDB 1. **下载**: 首先,你需要从HSQLDB的官方网站或者通过Git仓库获取最新的源码或二...

    ibatis 开发指南

    程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate&lt;br&gt;或者OJB 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握,&lt;br&gt;Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并...

    JBOSS数据库配置大全.pdf

    Informix是一款高性能的关系型数据库管理系统。 1. **添加JDBC驱动**: 将Informix的JDBC驱动程序复制到`server/default/lib`目录下。 2. **配置文件**: - 修改`informix-de.xml`配置文件中的`&lt;driver-class/&gt;`和`...

    Java数据库连接经典

    Java数据库连接(JDBC,Java Database Connectivity)是Java平台中用于与关系数据库交互的一组标准API,它允许Java开发者使用Java代码来访问和操作数据库。JDBC提供了统一的接口,使得开发者无需关心底层数据库的...

    三中数据库的常规操作DB2,Informix,Oracle

    1. 连接数据库:使用`db2 connect to &lt;database&gt; user &lt;username&gt; using &lt;password&gt;`命令,例如`db2 connect to sysdb user smp using smpaaa`。 2. 列出所有表:通过`db2 select tabname from syscat.tables`查询...

Global site tag (gtag.js) - Google Analytics