为什么我用唯一的order_id从数据库中order查询数据时返回了两条数据,这两条数据的order_id是不一样的

1、  本文只是面对数据库中order应用开發的程序员不适合专业DBA,DBA在数据库中order性能优化方面需要了解更多的知识;

2、  本文许多示例及概念是基于Oracle数据库中order描述对于其它关系型數据库中order也可以参考,但许多观点不适合于KV数据库中order或内存数据库中order或者是基于SSD技术的数据库中order;

3、  本文未深入数据库中order优化中最核心的執行计划分析技术

要正确的优化SQL,我们需要快速定位能性的瓶颈点也就是说快速找到我们SQL主要的开销在哪里?而大多数情况性能最慢嘚设备会是瓶颈点如下载时网络速度可能会是瓶颈点,本地复制文件时硬盘可能会是瓶颈点为什么这些一般的工作我们能快速确认瓶頸点呢,因为我们对这些慢速设备的性能数据有一些基本的认识如网络带宽是2Mbps,硬盘是每分钟7200转等等因此,为了快速找到SQL的性能瓶颈點我们也需要了解我们计算机系统的硬件基本性能指标,下图展示的当前主流计算机性能指标数据

从图上可以看到基本上每种设备都囿两个指标:

延时(响应时间):表示硬件的突发处理能力;

带宽(吞吐量):代表硬件持续处理能力。

从上图可以看出计算机系统硬件性能从高到代依次为:

由于SSD硬盘还处于快速发展阶段,所以本文的内容不涉及SSD相关应用系统

根据数据库中order知识,我们可以列出每种硬件主要的工作内容:

CPU及内存:缓存数据访问、比较、排序、事务检测、SQL解析、函数或逻辑运算;

网络:结果数据传输、SQL请求、远程数据库Φorder访问(dblink);

硬盘:数据访问、数据写入、日志记录、大数据量排序、大表连接

根据当前计算机硬件的基本性能指标及其在数据库中order中主要操作内容,可以整理出如下图所示的性能基本优化法则:

这个优化法则归纳为5个层次:

1、  减少数据访问(减少磁盘访问)

2、  返回更少數据(减少网络传输或磁盘访问)

3、  减少交互次数(减少网络传输)

由于每一层优化法则都是解决其对应硬件的性能问题所以带来的性能提升比例也不一样。传统数据库中order系统设计是也是尽可能对低速设备提供优化方法因此针对低速设备问题的可优化手段也更多,优化荿本也更低我们任何一个SQL的性能优化都应该按这个规则由上到下来诊断问题并提出解决方案,而不应该首先想到的是增加资源解决问题

以下是每个优化法则层级对应优化效果及成本经验参考:

接下来,我们针对5种优化法则列举常用的优化手段并结合实例分析

数据块是數据库中order中数据在磁盘中存储的最小单位,也是一次IO访问的最小单位一个数据块通常可以存储多条记录,数据块大小是DBA在创建数据库中order戓表空间时指定可指定为2K、4K、8K、16K或32K字节。下图是一个Oracle数据库中order典型的物理结构一个数据库中order可以包括多个数据文件,一个数据文件内叒包含多个数据块;

ROWID是每条记录在数据库中order中的唯一标识通过ROWID可以直接定位记录到对应的文件号及数据块位置。ROWID内容包括文件号、对像號、数据块号、记录槽号如下图所示:

1.1、创建并使用正确的索引

数据库中order索引的原理非常简单,但在复杂的表中真正能正确使用索引的囚很少即使是专业的DBA也不一定能完全做到最优。

索引会大大增加表记录的DML(INSERT,UPDATE,DELETE)开销正确的索引可以让性能提升100,1000倍以上不合理的索引也鈳能会让性能下降100倍,因此在一个表中创建什么样的索引需要平衡各种业务需求

常见的索引有B-TREE索引、位图索引、全文索引,位图索引一般用于数据仓库应用全文索引由于使用较少,这里不深入介绍B-TREE索引包括很多扩展类型,如组合索引、反向索引、函数索引等等以下昰B-TREE索引的简单介绍:

B-TREE索引也称为平衡树索引(Balance Tree),它是一种按字段排好序的树形目录结构主要用于提升查询性能和唯一约束支持。B-TREE索引的内嫆包括根节点、分支节点、叶子节点

叶子节点内容:索引字段内容+表记录ROWID

根节点,分支节点内容:当一个数据块中不能放下所有索引字段数据时就会形成树形的根节点或分支节点,根节点与分支节点保存了索引树的顺序及各层级间的引用关系

如果我们把一个表的内容認为是一本字典,那索引就相当于字典的目录如下图所示:

图中是一个字典按部首+笔划数的目录,相当于给字典建了一个按部首+笔划的組合索引

一个表中可以建多个索引,就如一本字典可以建多个目录一样(按拼音、笔划、部首等等)

一个索引也可以由多个字段组成,称为组合索引如上图就是一个按部首+笔划的组合目录。

SQL什么条件会使用索引

当字段上建有索引时,通常以下情况会使用索引:

SQL什么條件不会使用索引

不等于操作不能使用索引

经过普通运算或函数运算后的索引字段不能使用索引

含前导模糊查询的Like语法不能使用索引

B-TREE索引里不保存字段为NULL值记录,因此IS NULL不能使用索引

Oracle在做数值比较时需要将两边的数据转换成同一种数据类型如果两边数据类型不同时会对字段值隐式转换,相当于加了一层函数处理所以不能使用索引。

给索引查询的值应是已知数据不能是未知字段值。

经过函数运算字段的芓段要使用可以使用函数索引这种需求建议与DBA沟通。

有时候我们会使用多个字段的组合索引如果查询条件中第一个字段不能使用索引,那整个查询也不能使用索引

如:我们company表建了一个id+name的组合索引以下SQL是不能使用索引的

Oracle9i后引入了一种index skip scan的索引方式来解决类似的问题,但是通过index skip scan提高性能的条件比较特殊使用不好反而性能会更差。

我们一般在什么字段上建索引

这是一个非常复杂的话题,需要对业务及数据充分分析后再能得出结果主键及外键通常都要有索引,其它需要建索引的字段应满足以下条件:

1、字段出现在查询条件中并且查询条件可以使用索引;

2、语句执行频率高,一天会有几千次以上;

3、通过字段条件可筛选的记录集很小那数据筛选比例是多少才适合?

这个沒有固定值需要根据表数据量来评估,以下是经验公式可用于快速评估:

小表(记录数小于10000行的表):筛选比例<10%

大表:(筛选返回记录数)<(表总记录数*单条记录长度)/10000/16

以下是一些字段是否需要建B-TREE索引的经验分类:

有对像或身份标识意义字段

索引慎用字段,需要进行数据分布及使用場景详细评估

如何知道SQL是否使用了正确的索引?

简单SQL可以根据索引使用语法规则判断复杂的SQL不好办,判断SQL的响应时间是一种策略但是這会受到数据量、主机负载及缓存等因素的影响,有时数据全在缓存里可能全表访问的时间比索引访问时间还少。要准确知道索引是否囸确使用需要到数据库中order中查看SQL真实的执行计划,这个话题比较复杂详见SQL执行计划专题介绍。

这个没有固定的比例与每个表记录的夶小及索引字段大小密切相关,以下是一个普通表测试数据仅供参考:

因此对于写IO压力比较大的系统,表的索引需要仔细评估必要性叧外索引也会占用一定的存储空间。

1.2、只通过索引访问数据

有些时候我们只是访问表中的几个字段,并且字段内容较少我们可以为这幾个字段单独建立一个组合索引,这样就可以直接只通过访问索引就能得到数据一般索引占用的磁盘空间比表小很多,所以这种方式可鉯大大减少磁盘IO开销

如果这个SQL经常使用,我们可以在type,id,name上创建组合索引

有了这个组合索引后SQL就可以直接通过my_comb_index索引返回数据,不需要访问company表

还是拿字典举例:有一个需求,需要查询一本汉语字典中所有汉字的个数如果我们的字典没有目录索引,那我们只能从字典内容里┅个一个字计数最后返回结果。如果我们有一个拼音目录那就可以只访问拼音目录的汉字进行计数。如果一本字典有1000页拼音目录有20頁,那我们的数据访问成本相当于全表访问的50分之一

切记,性能优化是无止境的当性能可以满足需求时即可,不要过度优化在实际數据库中order中我们不可能把每个SQL请求的字段都建在索引里,所以这种只通过索引访问数据的方法一般只用于核心应用也就是那种对核心表訪问量最高且查询字段数据量很少的查询。

1.3、优化SQL执行计划

SQL执行计划是关系型数据库中order最核心的技术之一它表示SQL执行时的数据访问算法。由于业务需求越来越复杂表数据量也越来越大,程序员越来越懒惰SQL也需要支持非常复杂的业务逻辑,但SQL的性能还需要提高因此,優秀的关系型数据库中order除了需要支持复杂的SQL语法及更多函数外还需要有一套优秀的算法库来提高SQL性能。

目前ORACLE有SQL执行计划的算法约300种而苴一直在增加,所以SQL执行计划是一个非常复杂的课题一个普通DBA能掌握50种就很不错了,就算是资深DBA也不可能把每个执行计划的算法描述清楚虽然有这么多种算法,但并不表示我们无法优化执行计划因为我们常用的SQL执行计划算法也就十几个,如果一个程序员能把这十几个算法搞清楚那就掌握了80%的SQL执行计划调优知识。

由于篇幅的原因SQL执行计划需要专题介绍,在这里就不多说了

2.1.1、客户端(应用程序或浏览器)分页

将数据从应用服务器全部下载到本地应用程序或浏览器,在应用程序或浏览器内部通过本地代码进行分页处理

优点:编码简单减尐客户端与应用服务器网络交互次数

缺点:首次交互时间长,占用客户端内存

适应场景:客户端与应用服务器网络延时较大但要求后续操作流畅,如手机GPRS超远程访问(跨国)等等。

2.1.2、应用服务器分页

将数据从数据库中order服务器全部下载到应用服务器在应用服务器内部再進行数据筛选。以下是一个应用服务器端Java程序分页的示例:

优点:编码简单只需要一次SQL交互,总数据与分页数据差不多时性能较好

缺點:总数据量较多时性能较差。

适应场景:数据库中order系统不支持分页处理数据量较小并且可控。

采用数据库中orderSQL分页需要两次SQL完成

一个SQL返囙分页后的数据

缺点:编码复杂各种数据库中order语法不同,需要两次SQL交互

oracle数据库中order一般采用rownum来进行分页,常用分页语法有如下两种:

直接通过rownum分页:

数据访问开销=索引IO+索引全部记录结果对应的表数据IO

采用rowid分页语法

优化原理是通过纯索引找出分页记录的ROWID再通过ROWID回表返回数據,要求内层查询和排序字段全在索引里

数据访问开销=索引IO+索引分页结果对应的表数据IO

一个公司产品有1000条记录,要分页取其中20个产品假设访问公司索引需要50个IO,2条记录需要1个表数据IO

2.2、只返回需要的字段

通过去除不必要的返回字段可以提高性能,例:

1、减少数据在网络仩传输开销

2、减少服务器数据处理开销

3、减少客户端内存占用

4、字段变更时提前发现问题减少程序BUG

5、如果访问的所有字段刚好在一个索引里面,则可以使用纯索引访问提高性能

由于会增加一些编码工作量,所以一般需求通过开发规范来要求程序员这么做否则等项目上線后再整改工作量更大。

如果你的查询表中有大字段或内容较多的字段如备注信息、文件内容等等,那在查询表时一定要注意这方面的問题否则可能会带来严重的性能问题。如果表经常要查询并且请求大内容字段的概率很低我们可以采用分表处理,将一个大表分拆成兩个一对一的关系表将不常用的大内容字段放在一张单独的表中。如一张存储上传文件的表:

我们可以分拆成两张一对一的关系表:

数據库中order访问框架一般都提供了批量提交的接口jdbc支持batch的提交处理方法,当你一次性要往一个表中插入1000万条数据时如果采用普通的executeUpdate处理,那么和服务器交互次数为1000万次按每秒钟可以向数据库中order服务器提交10000次估算,要完成所有工作需要1000秒如果采用批量提交模式,1000条提交一佽那么和服务器交互次数为1万次,交互次数大大减少采用batch操作一般不会减少很多数据库中order服务器的物理IO,但是会大大减少客户端与服務端的交互次数从而减少了多次发起的网络延时开销,同时也会降低数据库中order的CPU开销

假设要向一个普通表插入1000万数据,每条记录大小為1K字节表上没有任何索引,客户端与数据库中order服务器网络是100Mbps以下是根据现在一般计算机能力估算的各种batch大小性能对比值:

从上可以看絀,Insert操作加大Batch可以对性能提高近8倍性能一般根据主键的Update或Delete操作也可能提高2-3倍性能,但不如Insert明显因为Update及Delete操作可能有比较大的开销在物理IO訪问。以上仅是理论计算值实际情况需要根据具体环境测量。

很多时候我们需要按一些ID查询数据库中order记录我们可以采用一个ID一个请求發给数据库中order,如下所示:

我们也可以做一个小的优化 如下所示,用ID INLIST的这种方式写SQL:

通过这样处理可以大大减少SQL请求的数量从而提高性能。那如果有10000个ID那是不是全部放在一条SQL里处理呢?答案肯定是否定的首先大部份数据库中order都会有SQL长度和IN里个数的限制,如ORACLE的IN里就不尣许超过1000个值

另外当前数据库中order一般都是采用基于成本的优化规则,当IN数量达到一定值时有可能改变SQL执行计划从索引访问变成全表访問,这将使性能急剧变化随着SQL中IN的里面的值个数增加,SQL的执行计划会更复杂占用的内存将会变大,这将会增加服务器CPU及内存成本

评估在IN里面一次放多少个值还需要考虑应用服务器本地内存的开销,有并发访问时要计算本地数据使用周期内的并发上限否则可能会导致內存溢出。

综合考虑一般IN里面的值个数超过20个以后性能基本没什么太大变化,也特别说明不要超过100超过后可能会引起执行计划的不稳萣性及增加数据库中orderCPU及内存成本,这个需要专业DBA评估

当我们采用select从数据库中order查询数据时,数据默认并不是一条一条返回给客户端的也鈈是一次全部返回客户端的,而是根据客户端fetch_size参数处理每次只返回fetch_size条记录,当客户端游标遍历到尾部时再从服务端取数据直到最后全蔀传送完成。所以如果我们要从服务端一次取大量数据时可以加大fetch_size,这样可以减少结果数据传输的交互次数及服务器数据准备时间提高性能。

以下是jdbc测试的代码采用本地数据库中order,表缓存在数据库中orderCACHE中因此没有网络连接及磁盘IO开销,客户端只遍历游标不做任何处悝,这样更能体现fetch参数的影响:

测试示例中的employee表有100000条记录每条记录平均长度135字节

以下是测试结果,对每种fetchsize测试5次再取平均值:

fetchsize默认值为10由上测试可以看出fetchsize对性能影响还是比较大的,但是当fetchsize大于100时就基本上没有影响了fetchsize并不会存在一个最优的固定值,因为整体性能与记录集大小及硬件平台有关根据测试结果建议当一次性要取大量数据时这个值设置为100左右,不要小于40注意,fetchsize不能设置太大如果一次取出嘚数据大于JVM的内存会导致内存溢出,所以建议不要超过1000太大了也没什么性能提高,反而可能会增加内存溢出的危险

注:图中fetchsize在128以后会囿一些小的波动,这并不是测试误差而是由于resultset填充到具体对像时间不同的原因,由于resultset已经到本地内存里了所以估计是由于CPU的L1,L2 Cache命中率变囮造成,由于变化不大所以笔者也未深入分析原因。

大型数据库中order一般都支持存储过程合理的利用存储过程也可以提高系统性能。如伱有一个业务需要将A表的数据做一些加工然后更新到B表中但是又不可能一条SQL完成,这时你需要如下3步操作:

a:将A表数据全部取出到客户端;

b:计算出要更新的数据;

c:将计算结果更新到B表

如果采用存储过程你可以将整个业务逻辑封装在存储过程里,然后在客户端直接调鼡存储过程处理这样可以减少网络交互的成本。

当然存储过程也并不是十全十美,存储过程有以下缺点:

a、不可移植性每种数据库Φorder的内部编程语法都不太相同,当你的系统需要兼容多种数据库中order时最好不要用存储过程

b、学习成本高,DBA一般都擅长写存储过程但并鈈是每个程序员都能写好存储过程,除非你的团队有较多的开发人员熟悉写存储过程否则后期系统维护会产生问题。

c、业务逻辑多处存茬采用存储过程后也就意味着你的系统有一些业务逻辑不是在应用程序里处理,这种架构会增加一些系统维护和调试成本

d、存储过程囷常用应用程序语言不一样,它支持的函数及语法有可能不能满足需求有些逻辑就只能通过应用程序处理。

e、如果存储过程中有复杂运算的话会增加一些数据库中order服务端的处理成本,对于集中式数据库中order可能会导致系统可扩展性问题

f、为了提高性能,数据库中order会把存儲过程代码编译成中间运行代码(类似于java的class文件)所以更像静态语言。当存储过程引用的对像(表、视图等等)结构改变后存储过程需要重新編译才能生效,在24*7高并发应用场景一般都是在线变更结构的,所以在变更的瞬间要同时编译存储过程这可能会导致数据库中order瞬间压力仩升引起故障(Oracle数据库中order就存在这样的问题)。

个人观点:普通业务逻辑尽量不要使用存储过程定时性的ETL任务或报表统计函数可以根据团队資源情况采用存储过程处理。

要通过优化业务逻辑来提高性能是比较困难的这需要程序员对所访问的数据及业务流程非常清楚。

某移动公司推出优惠套参活动对像为VIP会员并且2010年1,23月平均话费20元以上的客户。

如果我们修改业务逻辑为:

通过这样可以减少一些判断vip_flag的开销岼均话费20元以下的用户就不需要再检测是否VIP了。

如果程序员分析业务VIP会员比例为1%,平均话费20元以上的用户比例为90%那我们改成如下:

这樣就只有1%的VIP会员才会做检测平均话费,最终大大减少了SQL的交互次数

以上只是一个简单的示例,实际的业务总是比这复杂得多所以一般呮是高级程序员更容易做出优化的逻辑,但是我们需要有这样一种成本优化的意识

现在大部分Java框架都是通过jdbc从数据库中order取出数据,然后裝载到一个list里再处理list里可能是业务Object,也可能是hashmap

由于JVM内存一般都小于4G,所以不可能一次通过sql把大量数据装载到list里为了完成功能,很多程序员喜欢采用分页的方法处理如一次从数据库中order取1000条记录,通过多次循环搞定保证不会引起JVM Out of memory问题。

以下是实现此功能的代码示例t_employee表有10万条记录,设置分页大小为1000:

以上代码实际执行时间为6.516秒

很多持久层框架为了尽量让程序员使用方便封装了jdbc通过statement执行数据返回到resultset的細节,导致程序员会想采用分页的方式处理问题实际上如果我们采用jdbc原始的resultset游标处理记录,在resultset循环读取的过程中处理记录这样就可以┅次从数据库中order取出所有记录。显著提高性能

调整后的代码实际执行时间为3.156秒

从测试结果可以看出性能提高了1倍多,如果采用分页模式數据库中order每次还需发生磁盘IO的话那性能可以提高更多

iBatis等持久层框架考虑到会有这种需求,所以也有相应的解决方案在iBatis里我们不能采用queryForList嘚方法,而应用该采用queryWithRowHandler加回调事件的方式处理如下所示:

4、减少数据库中order服务器CPU运算

绑定变量是指SQL中对变化的值采用变量参数的形式提茭,而不是在SQL中直接拼写对应的值

Java中Preparestatement就是为处理绑定变量提供的对像,绑定变量有以下优点:

3、提高SQL解析性能不使用绑定变更我们一般称为硬解析,使用绑定变量我们称为软解析

第1和第2点很好理解,做编码的人应该都清楚这里不详细说明。关于第3点到底能提高多尐性能呢,下面举一个例子说明:

假设有这个这样的一个数据库中order主机:

100块磁盘每个磁盘支持IOPS为160

业务应用的SQL如下:

IO缓存命中率75%(索引全茬内存中,数据需要访问磁盘)

SQL软解析CPU消耗:0.02ms(常用经验值)

假设CPU每核性能是线性增长访问内存Cache中的IO时间忽略,要求计算系统对如上应鼡采用硬解析与采用软解析支持的每秒最大并发数:

磁盘IO支持最大并发数

从以上计算可以看出不使用绑定变量的系统当并发达到8000时会在CPU仩产生瓶颈,当使用绑定变量的系统当并行达到16000时会在磁盘IO上产生瓶颈所以如果你的系统CPU有瓶颈时请先检查是否存在大量的硬解析操作。

使用绑定变量为何会提高SQL解析性能这个需要从数据库中orderSQL执行原理说明,一条SQL在Oracle数据库中order中的执行过程如下图所示:

当一条SQL发送给数据庫中order服务器后系统首先会将SQL字符串进行hash运算,得到hash值后再从服务器内存里的SQL缓存区中进行检索如果有相同的SQL字符,并且确认是同一逻輯的SQL语句则从共享池缓存中取出SQL对应的执行计划,根据执行计划读取数据并返回结果给客户端

如果在共享池中未发现相同的SQL则根据SQL逻輯生成一条新的执行计划并保存在SQL缓存区中,然后根据执行计划读取数据并返回结果给客户端

为了更快的检索SQL是否在缓存区中,首先进荇的是SQL字符串hash值对比如果未找到则认为没有缓存,如果存在再进行下一步的准确对比所以要命中SQL缓存区应保证SQL字符是完全一致,中间囿大小写或空格都会认为是不同的SQL

如果我们不采用绑定变量,采用字符串拼接的模式生成SQL,那么每条SQL都会产生执行计划这样会导致共享池耗尽,缓存命中率也很低

一些不使用绑定变量的场景:

a、数据仓库应用,这种应用一般并发不高但是每个SQL执行时间很长,SQL解析的时間相比SQL执行时间比较小绑定变量对性能提高不明显。数据仓库一般都是内部分析应用所以也不太会发生SQL注入的安全问题。

b、数据分布鈈均匀的特殊逻辑如产品表,记录有1亿有一产品状态字段,上面建有索引有审核中,审核通过审核未通过3种状态,其中审核通过9500萬审核中1万,审核不通过499万

采用绑定变量的话,那么只会有一个执行计划如果走索引访问,那么对于审核中查询很快对审核通过囷审核不通过会很慢;如果不走索引,那么对于审核中与审核通过和审核不通过时间基本一样;

对于这种情况应该不使用绑定变量而直接采用字符拼接的方式生成SQL,这样可以为每个SQL生成不同的执行计划如下所示。

Oracle的排序算法一直在优化但是总体时间复杂度约等于nLog(n)。普通OLTP系统排序操作一般都是在内存里进行的对于数据库中order来说是一种CPU的消耗,曾在PC机做过测试单核普通CPU在1秒钟可以完成100万条记录的全内存排序操作,所以说由于现在CPU的性能增强对于普通的几十条或上百条记录排序对系统的影响也不会很大。但是当你的记录集增加到上万條以上时你需要注意是否一定要这么做了,大记录集排序不仅增加了CPU开销而且可能会由于内存不足发生硬盘排序的现象,当发生硬盘排序时性能会急剧下降这种需求需要与DBA沟通再决定,取决于你的需求和数据所以只有你自己最清楚,而不要被别人说排序很慢就吓倒

以下列出了可能会发生排序操作的SQL语法:

Union(并集),Union All也是一种并集操作但是不会发生排序,如果你确认两个数据集不需要执行去除重複数据操作那请使用Union All 代替Union。

Merge Join这是一种两个表连接的内部算法,执行时会把两个表先排序好再连接应用于两个大表连接的操作。如果伱的两个表连接的条件都是等值运算那可以采用Hash Join来提高性能,因为Hash Join使用Hash 运算来代替排序的操作具体原理及设置参考SQL执行计划优化专题。

我们SQL的业务逻辑经常会包含一些比较操作如a=b,a<b之类的操作对于这些比较操作数据库中order都体现得很好,但是如果有以下操作我们需偠保持警惕:

Like模糊查询,如下所示:

Like模糊查询对于数据库中order来说不是很擅长特别是你需要模糊检查的记录有上万条以上时,性能比较糟糕这种情况一般可以采用专用Search或者采用全文索引方案来提高性能。

不能使用索引定位的大量In List如下所示:

如果这里的a字段不能通过索引仳较,那数据库中order会将字段与in里面的每个值都进行比较运算如果记录数有上万以上,会明显感觉到SQL的CPU开销加大这个情况有两种解决方式:

a、  将in列表里面的数据放入一张中间小表,采用两个表Hash Join关联的方式处理;

b、  采用str2varList方法将字段串列表转换一个临时表处理关于str2varList方法可以茬网上直接查询,这里不详细介绍

以上两种解决方案都需要与中间表Hash Join的方式才能提高性能,如果采用了Nested Loop的连接方式性能会更差

如果发現我们的系统IO没问题但是CPU负载很高,就有可能是上面的原因这种情况不太常见,如果遇到了最好能和DBA沟通并确认准确的原因

4.4、大量复雜运算在客户端处理

什么是复杂运算,一般我认为是一秒钟CPU只能做10万次以内的运算如含小数的对数及指数运算、三角函数、3DES及BASE64数据加密算法等等。

如果有大量这类函数运算尽量放在客户端处理,一般CPU每秒中也只能处理1万-10万次这样的函数运算放在数据库中order内不利于高并發处理。

5.1、客户端多进程并行访问

多进程并行访问是指在客户端创建多个进程(线程)每个进程建立一个与数据库中order的连接,然后同时向数據库中order提交访问请求当数据库中order主机资源有空闲时,我们可以采用客户端多进程并行访问的方法来提高性能如果数据库中order主机已经很忙时,采用多进程并行访问性能不会提高反而可能会更慢。所以使用这种方式最好与DBA或系统管理员进行沟通后再决定是否采用

我们有10000個产品ID,现在需要根据ID取出产品的详细信息如果单线程访问,按每个IO要5ms计算忽略主机CPU运算及网络传输时间,我们需要50s才能完成任务洳果采用5个并行访问,每个进程访问2000个ID那么10s就有可能完成任务。

那是不是并行数越多越好呢开1000个并行是否只要50ms就搞定,答案肯定是否萣的当并行数超过服务器主机资源的上限时性能就不会再提高,如果再增加反而会增加主机的进程间调度成本和进程冲突机率

以下是┅些如何设置并行数的基本建议:

如果瓶颈在服务器主机,但是主机还有空闲资源那么最大并行数取主机CPU核数和主机提供数据服务的磁盤数两个参数中的最小值,同时要保证主机有资源做其它任务

如果瓶颈在客户端处理,但是客户端还有空闲资源那建议不要增加SQL的并荇,而是用一个进程取回数据后在客户端起多个进程处理即可进程数根据客户端CPU核数计算。

如果瓶颈在客户端网络那建议做数据压缩戓者增加多个客户端,采用map reduce的架构处理

如果瓶颈在服务器网络,那需要增加服务器的网络带宽或者在服务端将数据压缩后再处理了

5.2、數据库中order并行处理

数据库中order并行处理是指客户端一条SQL的请求,数据库中order内部自动分解成多个进程并行处理如下图所示:

并不是所有的SQL都鈳以使用并行处理,一般只有对表或索引进行全部访问时才可以使用并行数据库中order表默认是不打开并行访问,所以需要指定SQL并行的提示如下所示:

使用多进程处理,充分利用数据库中order主机资源(CPU,IO)提高性能。

1、单个会话占用大量资源影响其它会话,所以只适合在主機负载低时期使用;

2、只能采用直接IO访问不能利用缓存数据,所以执行前会触发将脏缓存数据写入磁盘操作

1、并行处理在OLTP类系统中慎鼡,使用不当会导致一个会话把主机资源全部占用而正常事务得不到及时响应,所以一般只是用于数据仓库平台

2、一般对于百万级记錄以下的小表采用并行访问性能并不能提高,反而可能会让性能更差

有时为了得到完整的结果我们需要从两个或更多的表中获取结果。我们就需要执行 join

数据库中order中的表可通过键将彼此联系起来。主键(Primary Key)是一个列在这个列中的每一荇的值都是唯一的。在表中每个主键的值都是唯一的。这样做的目的是在不重复每个表中的所有数据的情况下把表间的数据交叉捆绑茬一起。

请注意"Id_P" 列是 Persons 表中的的主键。这意味着没有两行能够拥有相同的 Id_P即使两个人的姓名完全相同,Id_P 也可以区分他们

请留意,"Id_P" 列把仩面的两个表联系了起来

我们可以通过引用两个表的方式,从两个表中获取数据:

谁订购了产品并且他们订购了什么产品?


    

除了上面嘚方法我们也可以使用关键词 JOIN 来从两个表中获取数据。

如果我们希望列出所有人的定购可以使用下面的 SELECT 语句:


    

除了我们在上面的例子Φ使用的 INNER JOIN(内连接),我们还可以使用其他几种连接

下面列出了您可以使用的 JOIN 类型,以及它们之间的差异

  • JOIN: 如果表中有至少一个匹配,則返回行
  • LEFT JOIN: 即使右表中没有匹配也从左表返回所有的行
  • RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
  • FULL JOIN: 只要其中一个表中存在匹配就返回荇

在整理准备面试的过程中先是茬网上一顿海搜,找到历史面试题然后一个骨头一个骨头的啃完,现在基本上这些问题(或者说叫做实践)都没有问题了遇到的困难昰:PL/SQL居多,T-SQL太少所以需要筛选,修改答案甚至有一些在T-SQL里面还没有支持。

下一步再把数据库中orderT-SQL经典教程在翻看一遍基本上对数据库Φorder就算告一段落了,前前后后共整整1个多月的时间(去年/looline/archive///post/O=o = 'c1')

我需要一个模式和一些数据来运行所要考核的查询列表A创建了所需的这些数据:

?  1:返回在2005年10月售出的所有产品的名称、价格和客户姓名,答案:

--或者下面的也行根据执行计划,二者是完全一样的

?  2:返回没有購买产品并且位于客户表格上的人的姓名及其客户ID,答案:

--或者下面的下面的是提供的答案;但是上面的效率更高,二者比4258

3:返回客户姓名、销售价格、建议售价、建议售价和实际价格的差额该差额必需是正数,答案见列表D:

?  4:根据产品类别计算平均价格答案见列表E:

?  5:将以下的客户和销售信息加入到数据库中order中:

?  6:从数据库中order中删除来自缅因洲(‘ME’)的客户,答案见列表G:(不过delete s from...这样的用法很怪,貌似这样就可以把s这个名字引入进来了)

?  7:返回客户购买了两个或多个产品的平均售价和产品类别答案:

?  9:根据产品种类计算建議售价超过实际售价10元及以上的销售数量,答案见列表J:

-- 题目有歧义所以,也可以这样做:

?  10:不使用叠代构建返回所由销售产品的銷售日期,以及该日期之前的销售额统计以及该日期之前的销售额统计,并按照该日期升序排列答案:

迄今为止,只有2个人可以正确哋回答出所有的问题

平均大约为50-60%,如果表现高于这个平均那么优秀的TSQL程序员,如果获得了90%以上的得分那么他或她就是一位非常优异嘚程序员。

我要回帖

更多关于 数据库中order 的文章

 

随机推荐