`

数据库优化法则详解

阅读更多

计算机系统硬件性能从高到代依次为:
CPU——Cache(L1-L2-L3)——内存——SSD硬盘——网络——硬盘
由于SSD硬盘还处于快速发展阶段,所以本文的内容不涉及SSD相关应用系统。
根据数据库知识,我们可以列出每种硬件主要的工作内容:
CPU及内存:缓存数据访问、比较、排序、事务检测、SQL解析、函数或逻辑运算;
网络:结果数据传输、SQL请求、远程数据库访问(dblink);
硬盘:数据访问、数据写入、日志记录、大数据量排序、大表连接。



 
图1

这个优化法则归纳为5个层次:
1、 减少数据访问(减少磁盘访问)
2、 返回更少数据(减少网络传输或磁盘访问)
3、 减少交互次数(减少网络传输)
4、 减少服务器CPU开销(减少CPU及内存开销)
5、 利用更多资源(增加资源)

 

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



 

图2

 

以下法则详解:

1、减少数据访问
1.1、创建并使用正确的索引
SQL什么条件会使用索引?
当字段上建有索引时,通常以下情况会使用索引:
INDEX_COLUMN = ?
INDEX_COLUMN > ?
INDEX_COLUMN >= ?
INDEX_COLUMN < ?
INDEX_COLUMN <= ?
INDEX_COLUMN between ? and ?
INDEX_COLUMN in (?,?,...,?)
INDEX_COLUMN like ?||'%'(后导模糊查询)
T1. INDEX_COLUMN=T2. COLUMN1(两个表通过索引字段关联)



 

 
图3  图4

注:
经过函数运算字段的字段要使用可以使用函数索引,这种需求建议
与DBA沟通。
有时候我们会使用多个字段的组合索引,如果查询条件中第一个字
段不能使用索引,那整个查询也不能使用索引
如:我们company表建了一个id+name的组合索引,以下SQL是不
能使用索引的
Select * from company where name=?
Oracle9i后引入了一种index skip scan的索引方式来解决类似的
问题,但是通过index skip scan提高性能的条件比较特殊,使用不好
反而性能会更差。

我们一般在什么字段上建索引?
这是一个非常复杂的话题,需要对业务及数据充分分析后再能得出结果。主键及外键通常都要有索
引,其它需要建索引的字段应满足以下条件:
1、字段出现在查询条件中,并且查询条件可以使用索引;
2、语句执行频率高,一天会有几千次以上;
3、通过字段条件可筛选的记录集很小,那数据筛选比例是多少才适合?
这个没有固定值,需要根据表数据量来评估,以下是经验公式,可用于快速评估:
小表(记录数小于10000行的表):筛选比例<10%;
大表:(筛选返回记录数)<(表总记录数*单条记录长度)/10000/16
单条记录长度≈字段平均内容长度之和+字段数*2

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

索引对DML(INSERT,UPDATE,DELETE)附加的开销有多少?
这个没有固定的比例,与每个表记录的大小及索引字段大小密切相关,以下是一个普通表测试数据,
仅供参考:
索引对于Insert性能降低56%
索引对于Update性能降低47%
索引对于Delete性能降低29%
因此对于写IO压力比较大的系统,表的索引需要仔细评估必要性,另外索引也会占用一定的存储
空间。

1.2、只通过索引访问数据
有些时候,我们只是访问表中的几个字段,并且字段内容较少,我们可以为这几个字段单独建立一
个组合索引,这样就可以直接只通过访问索引就能得到数据,一般索引占用的磁盘空间比表小很多,
所以这种方式可以大大减少磁盘IO开销。
如:select id,name from company where type='2';
如果这个SQL经常使用,我们可以在type,id,name上创建组合索引
create index my_comb_index on company(type,id,name);
有了这个组合索引后,SQL就可以直接通过my_comb_index索引返回数据,不需要访问company
表。
还是拿字典举例:有一个需求,需要查询一本汉语字典中所有汉字的个数,如果我们的字典没有目
录索引,那我们只能从字典内容里一个一个字计数,最后返回结果。如果我们有一个拼音目录,那就
可以只访问拼音目录的汉字进行计数。如果一本字典有1000页,拼音目录有20页,那我们的数据访
问成本相当于全表访问的50分之一。
切记,性能优化是无止境的,当性能可以满足需求时即可,不要过度优化。在实际数据库中
我们不可能把每个SQL请求的字段都建在索引里,所以这种只通过索引访问数据的方法一般只用于核
心应用,也就是那种对核心表访问量最高且查询字段数据量很少的查询。


1.3、优化SQL执行计划
SQL执行计划是关系型数据库最核心的技术之一,它表示SQL执行时的数据访问算法。由于业务
需求越来越复杂,表数据量也越来越大,程序员越来越懒惰,SQL也需要支持非常复杂的业务逻辑,
但SQL的性能还需要提高,因此,优秀的关系型数据库除了需要支持复杂的SQL语法及更多函数外,
还需要有一套优秀的算法库来提高SQL性能。
目前ORACLE有SQL执行计划的算法约300种,而且一直在增加,所以SQL执行计划是一个非常
复杂的课题,一个普通DBA能掌握50种就很不错了,就算是资深DBA也不可能把每个执行计划的算
法描述清楚。虽然有这么多种算法,但并不表示我们无法优化执行计划,因为我们常用的SQL执行计
划算法也就十几个,如果一个程序员能把这十几个算法搞清楚,那就掌握了80%的SQL执行计划调优
知识。
由于篇幅的原因,SQL执行计划需要专题介绍,在这里就不多说了。


2、返回更少的数据
2.1、数据分页处理
一般数据分页方式有:

2.1.1、客户端(应用程序或浏览器)分页
将数据从应用服务器全部下载到本地应用程序或浏览器,在应用程序或浏览器内部通过本地代码进
行分页处理
优点:编码简单,减少客户端与应用服务器网络交互次数
缺点:首次交互时间长,占用客户端内存
适应场景:客户端与应用服务器网络延时较大,但要求后续操作流畅,如手机GPRS,超远程访问
(跨国)等等。
2.1.2、应用服务器分页
将数据从数据库服务器全部下载到应用服务器,在应用服务器内部再进行数据筛选。以下是一个应
用服务器端Java程序分页的示例:
List list=executeQuery(“select * from employee order by id”);
Int count= list.size();
List subList= list.subList(10, 20);
优点:编码简单,只需要一次SQL交互,总数据与分页数据差不多时性能较好。
缺点:总数据量较多时性能较差。
适应场景:数据库系统不支持分页处理,数据量较小并且可控。
2.1.3、数据库SQL分页
采用数据库SQL分页需要两次SQL完成
一个SQL计算总数量
一个SQL返回分页后的数据
优点:性能好
缺点:编码复杂,各种数据库语法不同,需要两次SQL交互。

2.2、只返回需要的字段
通过去除不必要的返回字段可以提高性能,例:
调整前:select * from product where company_id=?;
调整后:select id,name from product where company_id=?;
优点:
1、减少数据在网络上传输开销
2、减少服务器数据处理开销
3、减少客户端内存占用
4、字段变更时提前发现问题,减少程序BUG
5、如果访问的所有字段刚好在一个索引里面,则可以使用纯索引访问提高性能。
缺点:增加编码工作量
由于会增加一些编码工作量,所以一般需求通过开发规范来要求程序员这么做,否则等项目上线后
再整改工作量更大。
如 果你的查询表中有大字段或内容较多的字段,如备注信息、文件内容等等,那在查询表时一定
要注意这方面的问题,否则可能会带来严重的性能问题。如果表经常要 查询并且请求大内容字段的概
率很低,我们可以采用分表处理,将一个大表分拆成两个一对一的关系表,将不常用的大内容字段放
在一张单独的表中。如一张存储上 传文件的表:
T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE,FILE_CONTENT)
我们可以分拆成两张一对一的关系表:
T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE)
T_FILECONTENT(ID, FILE_CONTENT)
通过这种分拆,可以大大提少T_FILE表的单条记录及总大小,这样在查询T_FILE时性能会更好,
当需要查询FILE_CONTENT字段内容时再访问T_FILECONTENT表。

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

3.2、In List
很多时候我们需要按一些ID查询数据库记录,我们可以采用一个ID一个请求发给数据库,如下所
示:
for :var in ids[] do begin
select * from mytable where id=:var;
end;
我们也可以做一个小的优化, 如下所示,用ID INLIST的这种方式写SQL:
select * from mytable where id in(:id1,id2,...,idn);
通过这样处理可以大大减少SQL请求的数量,从而提高性能。那如果有10000个ID,那是不是全
部放在一条SQL里处理呢?答案肯定是否定的。首先大部份数据库都会有SQL长度和IN里个数的限制,
如ORACLE的IN里就不允许超过1000个值。
另外当前数据库一般都是采用基于成本的优化规则,当IN数量达到一定值时有可能改变SQL执行
计划,从索引访问变成全表访问,这将使性能急剧变化。随着SQL中IN的里面的值个数增加,SQL的
执行计划会更复杂,占用的内存将会变大,这将会增加服务器CPU及内存成本。
评估在IN里面一次放多少个值还需要考虑应用服务器本地内存的开销,有并发访问时要计算本地
数据使用周期内的并发上限,否则可能会导致内存溢出。
综合考虑,一般IN里面的值个数超过20个以后性能基本没什么太大变化,也特别说明不要超过
100,超过后可能会引起执行计划的不稳定性及增加数据库CPU及内存成本,这个需要专业DBA评估。
3.3、设置Fetch Size
当我们采用select从数据库查询数据时,数据默认并不是一条一条返回给客户端的,也不是一次全
部返回客户端的,而是根据客户端fetch_size参数处理,每次只返回fetch_size条记录,当客户端游标
遍历到尾部时再从服务端取数据,直到最后全部传送完成。所以如果我们要从服务端一次取大量数据
时,可以加大fetch_size,这样可以减少结果数据传输的交互次数及服务器数据准备时间,提高性能。

3.4、使用存储过程
大型数据库一般都支持存储过程,合理的利用存储过程也可以提高系统性能。如你有一个业务需要
将A表的数据做一些加工然后更新到B表中,但是又不可能一条SQL完成,这时你需要如下3步操作:
a:将A表数据全部取出到客户端;
b:计算出要更新的数据;
c:将计算结果更新到B表。
如果采用存储过程你可以将整个业务逻辑封装在存储过程里,然后在客户端直接调用存储过程处理,
这样可以减少网络交互的成本。
当然,存储过程也并不是十全十美,存储过程有以下缺点:
a、不可移植性,每种数据库的内部编程语法都不太相同,当你的系统需要兼容多种数据库时最好
不要用存储过程。
b、学习成本高,DBA一般都擅长写存储过程,但并不是每个程序员都能写好存储过程,除非你的
团队有较多的开发人员熟悉写存储过程,否则后期系统维护会产生问题。
c、业务逻辑多处存在,采用存储过程后也就意味着你的系统有一些业务逻辑不是在应用程序里处
理,这种架构会增加一些系统维护和调试成本。
d、存储过程和常用应用程序语言不一样,它支持的函数及语法有可能不能满足需求,有些逻辑就
只能通过应用程序处理。
e、如果存储过程中有复杂运算的话,会增加一些数据库服务端的处理成本,对于集中式数据库可
能会导致系统可扩展性问题。
f、为了提高性能,数据库会把存储过程代码编译成中间运行代码(类似于java的class文件),所以
更像静态语言。当存储过程引用的对像(表、视图等等)结构改变后,存储过程需要重新编译才能生效,
在24*7高并发应用场景,一般都是在线变更结构的,所以在变更的瞬间要同时编译存储过程,这可能
会导致数据库瞬间压力上升引起故障(Oracle数据库就存在这样的问题)。
个人观点:普通业务逻辑尽量不要使用存储过程,定时性的ETL任务或报表统计函数可以根据团队
资源情况采用存储过程处理。

3.5、优化业务逻辑
要通过优化业务逻辑来提高性能是比较困难的,这需要程序员对所访问的数据及业务流程非常清楚。
举一个案例:
某移动公司推出优惠套参,活动对像为VIP会员并且2010年1,2,3月平均话费20元以上的客
户。
那我们的检测逻辑为:
select avg(money) as avg_money from bill where phone_no='13988888888' and date between
'201001' and '201003';
select vip_flag from member where phone_no='13988888888';
if avg_money>20 and vip_flag=true then
begin
执行套参();
end;
如果我们修改业务逻辑为:
select avg(money) as avg_money from bill where phone_no='13988888888' and date between
'201001' and '201003';
if avg_money>20 then
begin
select vip_flag from member where phone_no='13988888888';
if vip_flag=true then
begin
执行套参();
end;
end;
通过这样可以减少一些判断vip_flag的开销,平均话费20元以下的用户就不需要再检测是否VIP
了。
如果程序员分析业务,VIP会员比例为1%,平均话费20元以上的用户比例为90%,那我们改成如
下:
select vip_flag from member where phone_no='13988888888';
if vip_flag=true then
begin
select avg(money) as avg_money from bill where phone_no='13988888888' and date between
'201001' and '201003';
if avg_money>20 then
begin
执行套参();
end;
end;
这样就只有1%的VIP会员才会做检测平均话费,最终大大减少了SQL的交互次数。
以上只是一个简单的示例,实际的业务总是比这复杂得多,所以一般只是高级程序员更容易做出优
化的逻辑,但是我们需要有这样一种成本优化的意识。
3.6、使用ResultSet游标处理记录
现在大部分Java框架都是通过jdbc从数据库取出数据,然后装载到一个list里再处理,list里可能
是业务Object,也可能是hashmap。
由于JVM内存一般都小于4G,所以不可能一次通过sql把大量数据装载到list里。为了完成功能,
很多程序员喜欢采用分页的方法处理,如一次从数据库取1000条记录,通过多次循环搞定,保证不会
引起JVM Out of memory问题。
以下是实现此功能的代码示例,t_employee表有10万条记录,设置分页大小为1000:
d1 = Calendar.getInstance().getTime();
vsql = "select count(*) cnt from t_employee";
pstmt = conn.prepareStatement(vsql);
ResultSet rs = pstmt.executeQuery();
Integer cnt = 0;
while (rs.next()) {
cnt = rs.getInt("cnt");
}I
nteger lastid=0;
Integer pagesize=1000;
System.out.println("cnt:" + cnt);
String vsql = "select count(*) cnt from t_employee";
PreparedStatement pstmt = conn.prepareStatement(vsql);
ResultSet rs = pstmt.executeQuery();
Integer cnt = 0;
while (rs.next()) {
cnt = rs.getInt("cnt");
}I
nteger lastid = 0;
Integer pagesize = 1000;
System.out.println("cnt:" + cnt);
for (int i = 0; i <= cnt / pagesize; i++) {
vsql = "select * from (select * from t_employee where id>? order by id) where rownum<=?";
pstmt = conn.prepareStatement(vsql);
pstmt.setFetchSize(1000);
pstmt.setInt(1, lastid);
pstmt.setInt(2, pagesize);
rs = pstmt.executeQuery();
int col_cnt = rs.getMetaData().getColumnCount();
Object o;
while (rs.next()) {
for (int j = 1; j <= col_cnt; j++) {
o = rs.getObject(j);
}
lastid = rs.getInt("id");
}
rs.close();
pstmt.close();
}
以上代码实际执行时间为6.516秒
很多持久层框架为了尽量让程序员使用方便,封装了jdbc通过statement执行数据返回到
resultset的细节,导致程序员会想采用分页的方式处理问题。实际上如果我们采用jdbc原始的
resultset游标处理记录,在resultset循环读取的过程中处理记录,这样就可以一次从数据库取出所有
记录。显著提高性能。
这里需要注意的是,采用resultset游标处理记录时,应该将游标的打开方式设置为
FORWARD_READONLY模式(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY),否则
会把结果缓存在JVM里,造成JVM Out of memory问题。
代码示例:
String vsql ="select * from t_employee";
PreparedStatement pstmt =
conn.prepareStatement(vsql,ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
pstmt.setFetchSize(100);
ResultSet rs = pstmt.executeQuery(vsql);
int col_cnt = rs.getMetaData().getColumnCount();
Object o;
while (rs.next()) {
for (int j = 1; j <= col_cnt; j++) {
o = rs.getObject(j);
}
}
调整后的代码实际执行时间为3.156秒
从测试结果可以看出性能提高了1倍多,如果采用分页模式数据库每次还需发生磁盘IO的话那性
能可以提高更多。
iBatis等持久层框架考虑到会有这种需求,所以也有相应的解决方案,在iBatis里我们不能采用
queryForList的方法,而应用该采用queryWithRowHandler加回调事件的方式处理,如下所示:
MyRowHandler myrh=new MyRowHandler();
sqlmap.queryWithRowHandler("getAllEmployee", myrh);
class MyRowHandler implements RowHandler {
public void handleRow(Object o) {
//todo something
}
}
iBatis的queryWithRowHandler很好的封装了resultset遍历的事件处理,效果及性能与resultset
遍历一样,也不会产生JVM内存溢出。


4、减少数据库服务器CPU运算
4.1、使用绑定变量
绑定变量是指SQL中对变化的值采用变量参数的形式提交,而不是在SQL中直接拼写对应的值。
非绑定变量写法:Select * from employee where id=1234567
绑定变量写法:
Select * from employee where id=?
Preparestatement.setInt(1,1234567)
Java中Preparestatement就是为处理绑定变量提供的对像,绑定变量有以下优点:
1、防止SQL注入
2、提高SQL可读性
3、提高SQL解析性能,不使用绑定变更我们一般称为硬解析,使用绑定变量我们称为软解析。

4.2、合理使用排序
Oracle的排序算法一直在优化,但是总体时间复杂度约等于nLog(n)。普通OLTP系统排序操作一
般都是在内存里进行的,对于数据库来说是一种CPU的消耗,曾在PC机做过测试,单核普通CPU在1
秒钟可以完成100万条记录的全内存排序操作,所以说由于现在CPU的性能增强,对于普通的几十条
或上百条记录排序对系统的影响也不会很大。但是当你的记录集增加到上万条以上时,你需要注意是
否一定要这么做了,大记录集排序不仅增加了CPU开销,而且可能会由于内存不足发生硬盘排序的现
象,当发生硬盘排序时性能会急剧下降,这种需求需要与DBA沟通再决定,取决于你的需求和数据,
所以只有你自己最清楚,而不要被别人说排序很慢就吓倒。
以下列出了可能会发生排序操作的SQL语法:
Order by
Group by
Distinct
Exists子查询
Not Exists子查询
In子查询
Not In子查询
Union(并集),Union All也是一种并集操作,但是不会发生排序,如果你确认两个数据集不需要执行
去除重复数据操作,那请使用Union All 代替Union。
Minus(差集)
Intersect(交集)
Create Index
Merge Join,这是一种两个表连接的内部算法,执行时会把两个表先排序好再连接,应用于两个大表连
接的操作。如果你的两个表连接的条件都是等值运算,那可以采用Hash Join来提高性能,因为Hash
Join使用Hash 运算来代替排序的操作。具体原理及设置参考SQL执行计划优化专题。
4.3、减少比较操作
我们SQL的业务逻辑经常会包含一些比较操作,如a=b,a<b之类的操作,对于这些比较操作数
据库都体现得很好,但是如果有以下操作,我们需要保持警惕:
Like模糊查询,如下所示:
a like ‘%abc%’
Like模糊查询对于数据库来说不是很擅长,特别是你需要模糊检查的记录有上万条以上时,性能比
较糟糕,这种情况一般可以采用专用Search或者采用全文索引方案来提高性能。
不能使用索引定位的大量In List,如下所示:
a in (:1,:2,:3,…,:n) ----n>20
如果这里的a字段不能通过索引比较,那数据库会将字段与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万次这样的
函数运算,放在数据库内不利于高并发处理。
5、利用更多的资源
5.1、客户端多进程并行访问
多进程并行访问是指在客户端创建多个进程(线程),每个进程建立一个与数据库的连接,然后同时
向数据库提交访问请求。当数据库主机资源有空闲时,我们可以采用客户端多进程并行访问的方法来
提高性能。如果数据库主机已经很忙时,采用多进程并行访问性能不会提高,反而可能会更慢。所以
使用这种方式最好与DBA或系统管理员进行沟通后再决定是否采用。
例如:
我们有10000个产品ID,现在需要根据ID取出产品的详细信息,如果单线程访问,按每个IO要
5ms计算,忽略主机CPU运算及网络传输时间,我们需要50s才能完成任务。如果采用5个并行访问,
每个进程访问2000个ID,那么10s就有可能完成任务。
那是不是并行数越多越好呢,开1000个并行是否只要50ms就搞定,答案肯定是否定的,当并行
数超过服务器主机资源的上限时性能就不会再提高,如果再增加反而会增加主机的进程间调度成本和
进程冲突机率。
以下是一些如何设置并行数的基本建议:
如果瓶颈在服务器主机,但是主机还有空闲资源,那么最大并行数取主机CPU核数和主机提供数
据服务的磁盘数两个参数中的最小值,同时要保证主机有资源做其它任务。
如果瓶颈在客户端处理,但是客户端还有空闲资源,那建议不要增加SQL的并行,而是用一个进
程取回数据后在客户端起多个进程处理即可,进程数根据客户端CPU核数计算。
如果瓶颈在客户端网络,那建议做数据压缩或者增加多个客户端,采用map reduce的架构处理。
如果瓶颈在服务器网络,那需要增加服务器的网络带宽或者在服务端将数据压缩后再处理了。
5.2、数据库并行处理
数据库并行处理是指客户端一条SQL的请求,数据库内部自动分解成多个进程并行处理,如下图
所示:



 

图5


并不是所有的SQL都可以使用并行处理,一般只有对表或索引进行全部访问时才可以使用并行。
数据库表默认是不打开并行访问,所以需要指定SQL并行的提示,如下所示:
select /*+parallel(a,4)*/ * from employee;
并行的优点:
使用多进程处理,充分利用数据库主机资源(CPU,IO),提高性能。
并行的缺点:
1、单个会话占用大量资源,影响其它会话,所以只适合在主机负载低时期使用;
2、只能采用直接IO访问,不能利用缓存数据,所以执行前会触发将脏缓存数据写入磁盘操作。
注:
1、并行处理在OLTP类系统中慎用,使用不当会导致一个会话把主机资源全部占用,而正常事务
得不到及时响应,所以一般只是用于数据仓库平台。
2、一般对于百万级记录以下的小表采用并行访问性能并不能提高,反而可能会让性能更差。

  • 大小: 43.9 KB
  • 大小: 77.7 KB
  • 大小: 139.9 KB
  • 大小: 90.8 KB
  • 大小: 41.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics