1. 从foxpro的大数据量(超过12万条)DBF导出到Excel的问题,我想没5000条数据导出一个EX
假设你的大数据量表取名“信息表”,如下程序将可以帮助你将它按要求导出。
use 信息表专
count to 记录属数
首记录=1
for t=1 to ceiling(记录数/5000)
if t*5000>记录数
末记录=记录数
else
末记录=t*5000
endif
表名=iif(t<10,"0"+allt(str(t))+".xls",allt(str(t))+".xls")
to &表名 xls for recn()>=首记录.and.recn()<=末记录
首记录=末记录+1
endf
如果你对命令不熟悉,建议你直接用复制加粘贴的办法来创建这个程序文件,运行后就可以在你的默认目录下生成你所需要的全部Excel表文件了。
2. ORACLE大数据表Update处理
ORACLE中如果表数据量很大(M级或更大) update某个字段是很慢的(如我的HIS项目中更新历史业务流程表 万条记录 用CURSOR来更新 条MIT一次 花了 天也没更新完) 后来尝试过的改进办法有
把表上的LOGGING取消
把表上的INDEX取消
但是依然很慢 无奈下找到这个
没陪在这个主题问答里 ORA官方提了一种处理的办法
利用CREATE table as select xxxxx的办法来生成一新表T
在T 上创建与目标表一样的索引
把目标表删除或RENAME(注意备份以备反悔)
把T 改名成目标表
试了一下 果然非常岁察如地快 我的任务差不多在 Min就完成了
如csywdk table_room是一张大表 要删除其中bakfwid在noNewYWFW 中的记录 且要更新bakfwid在imp_table_room中记录的ROOM_LOC为imp_table_room room_loc:
( )创建新表
create table tmp_new_table_room as
select t ROOM_ID t NEWROOMID t BUILDID t TFH t DKH t BUILD_NO t LAYER_NO t ROOM_NO t ROOM_NAME
decode(t bakfwid null t ROOM_LOC t room_loc)
t ROOM_AREA
t SURTYPE t LAYER_NAME t DEVDEP t CELL t DELFLAG t QXXZ t SjsJLSH t FD t ID t BAKFWID
from csywdk table_room t left join imp_table_room t on t bakfwid=t bakfwid
where not exists(select from noNewYWFW t where t bakfwid=t bakfwid)
( )创建备份表
create table Table_room as
select * from csywdk table_room
( )替换原表
drop table sde table_room
create table sde table_room as
select * from tmp_new_table_room
在这个问答里还提到一句ORA PL/SQL效率相关的话
能用一句语句处理的任务决不乎启要用多句编程来实现
lishixin/Article/program/Oracle/201311/18980
3. 大型数据库设计原则
一个好的数据库产品不等于就有一个好的应用系统 如果不能设计一个合理的数据库模型 不仅会增加客户端和服务器段程序的编程和维护的难度 而且将会影响系统实际运行的性能 一般来讲 在一个MIS系统分析 设计 测试和试运行阶段 因为数据量较小 设计人员和测试人员往往只注意到功能的实现 而很难注意到性能的薄弱之处 等到系统投入实际运行一段时间后 才发现系统的性能在降低 这时再来考虑提高系统性能则要花费更多的人力物力 而整个系统也不可避免的形成了一个打补丁工程 笔者依据多年来设计和使用数据库的经验 提出以下一些设计准则 供同仁们参考
命名的规范
不同的数据库产品对对象的命名有不同的要求 因此 数据库中的各种对象的命名 后台程序的代码编写应采用大小写敏感的形式 各种对象命名长度不要超过 个字符 这样便于应用系统适应不同的数据库
游标(Cursor)的慎用
游标提供了对特定集合中逐行扫描的手段 一般使用游标逐行遍历数据 根据取出的数据不同条件进行不同的操作 尤其对多表和大表定义的游标(大的数据集合)循环很容易使程序进入一个漫长的等特甚至死机 笔者在某市《住房公积金管理系统》进行日终帐户滚积数计息处理时 对一个 万个帐户的游标处理导致程序进入了一个无限期的等特(后经测算需 个小时才能完成)(硬件环境 Alpha/ Mram Sco Unix Sybase ) 后根据不同的条件改成用不同的UPDATE语句得以在二十分钟之内完成 示例如下
Declare Mycursor cursor for select count_no from COUNT
Open Mycursor
Fetch Mycursor into @vcount_no
While (@@sqlstatus= )
Begin
If @vcount_no= 条件
操作
If @vcount_no= 条件
操作
Fetch Mycursor into @vcount_no
End
改为
Update COUNT set 操作 for 条件
Update COUNT set 操作 for 条件
在有些场合 有时也非得使用游标 此时也可考虑将符合条件的数据行转入临时表中 再对临时表定义游标进行操作 可时性能得到明显提高 笔者在某地市〈电信收费系统〉数据库后台程序设计中 对一个表( 万行中符合条件的 多行数据)进行游标操作(硬件环境 PC服务器 PII Mram NT Ms Sqlserver ) 示例如下
Create #tmp /* 定义临时表 */
(字段
字段
)
Insert into #tmp select * from TOTAL where
条件 /* TOTAL中 万行 符合条件只有几十行 */
Declare Mycursor cursor for select * from #tmp
/*对临时表定义游标*/
索引(Index)的使用原则
创建索引一般有以下两个目的 维护被索引列的唯一性和提供快速访问表中数据的策略 大型数据库有两种索引即簇索引和非簇索引 一个没有簇索引的表是按堆结构存储数据 所有的数据均添加在表的尾部 而建立了簇索引的表 其数据在物理上会按照簇索引键的顺序存储 一个表只允许有一个簇索引 因此 根据B树结构 可以理解添加任何一种索引均能提高按索引列查询的速度 但会降低插入 更新 删除操作的性能 尤其是当填充因子(Fill Factor)较大时 所以对索引较多的表进行频繁的插入 更新 删除操作 建表和索引时因设置较小的填充因子 以便在各数据页中留下较多的自由空间 减少页分割及重新组织的工作
数据的一致性和完整性
为了保证数据库的一致性和完整性 设计人员往往会设计过多的表间关联(Relation) 尽可能的降低数据的冗余 表间关联是一种强制性措施 建立后 对父表(Parent Table)和子表(Child Table)的插入 更新 删除操作均要占用系统的开销 另外 最好不要用Identify 属性字段作为主键与子表关联 如果数据冗余低 数据的完整性容易得到保证 但增加了表间连接查询的操作 为了提高系统的响应时间 合理的数据冗余也是必要的 使用规则(Rule)和约束(Check)来防止系统操作人员误输入造成数据的错误是设计人员的另一种常用手段 但是 不必要的规则和约束也会占用系统的不必要开销 需要注意的是 约束对数据的有效性验证要比规则快 所有这些 设计人员在设计阶段应根据系统操作的类型 频度加以均衡考虑
事务的陷阱
事务是在一次性完成的一组操作 虽然这些操作是单个的操作 SQL Server能够保证这组操作要么全部都完成 要么一点都不做 正是大型数据库的这一特性 使得数据的完整性得到了极大的保证
众所周知 SQL Server为每个独立的SQL语句都提供了隐含的事务控制 使得每个DML的数据操作得以完整提交或回滚 但是SQL Server还提供了显式事务控制语句
BEGIN TRANSACTION 开始一个事务
MIT TRANSACTION 提交一个事务
ROLLBACK TRANSACTION 回滚一个事务
事务可以嵌套 可以通过全局变量@@trancount检索到连接的事务处理嵌套层次 需要加以特别注意并且极容易使编程人员犯错误的是 每个显示或隐含的事物开始都使得该变量加 每个事务的提交使该变量减 每个事务的回滚都会使得该变量置 而只有当该变量为 时的事务提交(最后一个提交语句时) 这时才把物理数据写入磁盘
数据库性能调整
在计算机硬件配置和网络设计确定的情况下 影响到应用系统性能的因素不外乎为数据库性能和客户端程序设计 而大多数数据库设计员采用两步法进行数据库设计 首先进行逻辑设计 而后进行物理设计 数据库逻辑设计去除了所有冗余数据 提高了数据吞吐速度 保证了数据的完整性 清楚地表达数据元素之间的关系 而对于多表之间的关联查询(尤其是大数据表)时 其性能将会降低 同时也提高了客 户端程序的编程难度 因此 物理设计需折衷考虑 根据业务规则 确定对关联表的数据量大小 数据项的访问频度 对此类数据表频繁的关联查询应适当提高数据冗余设计
数据类型的选择
数据类型的合理选择对于数据库的性能和操作具有很大的影响 有关这方面的书籍也有不少的阐述 这里主要介绍几点经验
Identify字段不要作为表的主键与其它表关联 这将会影响到该表的数据迁移
Text 和Image字段属指针型数据 主要用来存放二进制大型对象(BLOB) 这类数据的操作相比其它数据类型较慢 因此要避开使用
日期型字段的优点是有众多的日期函数支持 因此 在日期的大小比较 加减操作上非常简单 但是 在按照日期作为条件的查询操作也要用函数 相比其它数据类型速度上就慢许多 因为用函数作为查询的条件时 服务器无法用先进的性能策略来优化查询而只能进行表扫描遍历每行
例如 要从DATA_TAB 中(其中有一个名为DATE的日期字段)查询 年的所有记录
lishixin/Article/program/Oracle/201311/17929
4. 浅谈Oracle中大数据量表的管理
简介
随着信息业的发展 在企业级数据库应用中 经常会有一些几十GB 上百GB的数据表 这些大数据量表的设计 维护及其备份都是数据库管理中的重点及其难点 本文就从设计 维护及其备份方面探讨一下大数据量表的管理
设计
大表时效性
大数据量表的数据量一般来说是跟时间成正比的 时间越久 数据量越大 在设计阶段首先要考虑这些大表的时效性
通常情况 在一定的时间区间 数据的访问频度比较大 超过这个区间 数据的访问频度极小 这个时间区间根据不同的应用类型而不同 通常是几个月 超过这个时间区间的数据可以认为是历史数据 数据访问的可能性不打 在企业应用中 并不是所有的数据都需要保留在生产数据库中 对于这些历史数据 可以考虑离线存放 或者是存放在另外的数据库中 比如数据仓库等
大表的时效性可以通过在表上加时间戳列来实现
使用分区表
Oracle 以后提供了分区表的功能 分区表可以把一个表的数据从物理和逻辑上分割成小的区域 Oracle支持非常大的分区表 一个对象可以允许多达 个分区 对于大表来说 使用分区表是首选方案 分区表可以改善表的维护 备份 恢复及查询性能
分区表有 种分区方式
n Range Partitioning
n Hash Partitioning
n Composite Partitioning
n List Partitioning
对于有时效性的大表 可以采用按时间分区的 Range Partitioning表 例如按天分区的分区表
CREATE TABLE Test(
DATATIME DATE NOT NULL
P NUMBER NULL
P NUMBER NULL
P NUMBER NULL
P NUMBER NULL
P NUMBER NULL
P NUMBER NULL
P NUMBER NULL
P NUMBER NULL
CONSTRAINT PK_TEST PRIMARY KEY (datatime p p ) USING INDEX LOCAL TABLESPACE USERINDEX
)
PARTITION BY RANGE (DATATIME)
(PARTITION Test_ VALUES LESS THAN (TO_DATE( YYYY MM DD ))
(PARTITION Test_ VALUES LESS THAN (TO_DATE( YYYY MM DD ))
……
);
对于按时间分区仍然不能满足性能需求的表 还可以根据应用需求 使用子分区对表进一步细化
应用设计中 要充分利用分区表的特性 对大表的访问要完全避免全表访问 缩小访问范围 在查询条件中 尽量使用分区的列
维护
大表的维护工作比较繁琐 索引的维护 存储空间的维护 历史数据的清理等等 使用分区表可以简化大表的维护工作 但是如果表很多的话 手动的创建 删除分区也是一件很繁琐 而且容易出错的事情
此章节以按天分区的分区表为例讨论大表的自动维护
分区表的命名规则
分区表分区的命名应当按照一定的规则命名 以利于自动维护的实现 本例采用按天分区的分区表 分区的命名方式为TABLENAME_YYMMDD 例如 TEST表的 年 月 日的分区命名为TEST _
维护字典
在数据库中创建维护字典表 存放需要自动维护的分区表的信息 包括表名 schema 表的类型 数据在数据库中的保留时间等信息
Table Name: H_RETENTION
Column Type Null? Description
tablename Varchar ( ) Not null 表名
schemaname Varchar ( ) Not null Schema
typeid Varchar ( ) Not null 表类型 PARTITION NORMAL …
retention Number( ) Not null 该表的保存天数
自动创建分区
对于按时间分区的分区表 若不能及时创建新的数据分区 会导致数据无法插入到分区表的严重后果 数据库会产生报错信息ORA : inserted partition key does not map to any partition 插入失败
创建分区可以手工创建 也可以根据维护字典 通过系统的任务调度来创建分区 通常是在月底创建下个月的分区
自动创建分区实现如下
/**************************************************************************
Program Name:Add_Partition
Description:
创建某个用户下个月的所有分区
***************************************************************************/
PROCEDURE add_partition (v_schema IN VARCHAR )
IS
CURSOR c_td_table
IS
SELECT tablename
FROM h_retention
WHERE typeid = PARTITION
AND schemaname = UPPER (v_schema)
ORDER BY tablename;
v_cur BINARY_INTEGER;
v_int BINARY_INTEGER;
v_partition VARCHAR ( );
v_date DATE;
v_days NUMBER;
sql_stmt VARCHAR ( ); String used to save sql statement
err_msg VARCHAR ( );
BEGIN
v_date := TRUNC (ADD_MONTHS (SYSDATE ) MM );
v_days :=
TO_NUMBER (TO_CHAR (LAST_DAY (ADD_MONTHS (SYSDATE )) DD ));
v_cur := DBMS_SQL open_cursor;
FOR v_table IN c_td_table
LOOP
v_date := TRUNC (ADD_MONTHS (SYSDATE ) MM );
v_partition := v_table tablename;
FOR i IN v_days
LOOP
BEGIN
sql_stmt :=
ALTER TABLE
|| v_schema
||
|| v_table tablename
|| ADD PARTITION
|| v_partition
|| _
|| TO_CHAR (v_date YYMMDD )
||
|| VALUES LESS THAN (TO_DATE(
|| TO_CHAR (v_date + YYYY MM DD )
|| YYYY MM DD )) ;
DBMS_SQL parse (v_cur sql_stmt DBMS_SQL native);
v_int := DBMS_SQL EXECUTE (v_cur);
EXCEPTION
WHEN OTHERS
THEN
err_msg :=
v_partition
|| : Create
|| TO_CHAR (v_date YYMMDD )
|| partition unsuccessfully! Error Information:
|| SQLERRM;
log_insert (err_msg); You can define your own log_insert function
MIT;
END;
v_date := v_date + ;
END LOOP;
END LOOP;
DBMS_SQL close_cursor (v_cur);
END;
自动删除过期分区
为了释放存储空间并提高大表的性能 要从数据库中删除大表中过期的历史数据 删除操作可以手工执行 也可以通过系统的任务调度来自动删除 分区表数据删除只需要删除相应的数据分区 与delete相比 有如下好处
u 速度快
u 占用回滚表空间少
u 产生日志量少
u 释放空间
如果有global的索引 删除分区后需要重建索引
自动删除分区实现如下
lishixin/Article/program/Oracle/201311/18275
5. android的Cursor.requery()方法过时怎么办
Cursor.requery()方法 是过时了。如果数据量大,会导致重写读取的事件长(也就是requery()的执行时间)。在数据库数据少的时候,我们仍然可以安全地使用requery。但吵猛是对于具有大量数据时,就不建议使扒枣用了。
SimpleCursorAdapter adapter=new SimpleCursorAdapter(context, layout, cursor, from, to, flags);
当你插入数据时,参数cursor 的数据必须要变化才会更新,所以你要将cursor 从新 进行赋值(春碰拆注意 cursor不是新的实例),再调用notifyDataSetChanged();
6. oracle 一个游标可存多大的数据量
游标和指针我理解是一个意思的
它只是用来描述取得内存中数据的方式
就像导航一样,GPS会给你地图上的位置,而能不能跑到,取决与你的车里有多少油
例如:
在数据库中查询 取到一个结果集 你能不能取到那些数据,取决于你的机器 假如结果集中有一个CLOB类型字段 而你的机器,内存+硬盘总共250M 没可能看到数据,对吧
修改最大游标: alter system set open_cursor=800, scope=both;
只要你能接受性能,随便你改,另外 open_cursor是整形 改得越大,性能越受影响
以下来自“奔驰M888”的回答
1、plsql是面向过程的语言,这类语言还有c,cobol等,这类语言的共同点是一次只能处理一条数据,而数据库sql返回的对象是一个集合,这样直接用plsql程序操作就会出现问题。
2、在这种环境下就出现了游标,游标实际是一个内存地址,只想的是sql查询出的结果集,当需要的时候再根据游标一条一条取数据【fetch】,直到全部数据取完。
就像chsoftstar说的那样 出现游标无法取数的问题,很大可能是写错了,具体什么原因,还得楼主自己查找了
7. 如何看当前最大打开cursor数量是多少
方腊大轮法如仿段下轮信:
select s.USERNAME,S.sid,s.SERIAL#,p.SPID, osuser, machine, count(*) num_curs
from v$open_cursor o, v$session s,v$process p
where /*user_name = '' and*/ o.sid=s.sid and p.ADDR=s.PADDR
group by s.USERNAME,S.sid,s.SERIAL#,p.SPID, osuser, machine
order by num_curs desc;
8. 存储过程中用什么可以替代游标
Mysql存储过程优化——使用临时表代替游标。
Mysql游标在操作小数据量时比较方便,效率可观,但操作大数据量,速度比较慢前运,甚至直接产生系统错误。
一般说来,当操作的数据超过1万条时,就避免用游标吧。
为了测试游标性能,写了下面一个游标对IDC_Gather_Info表中数据进行遍历
下面是当表中数据分别为15万、5万、1万时游标的表现:
1.数据量15万,存储过程执行失败,提迟消示错误:Incorrect
key
file
for
table
'/tmp/#sql_3044_0.MYI';try
to
repair
it
2.数据量5万,执行成功,耗时31.051s
3.数据量1万,执行成功,耗时1.371s
下面使用临时表替换游标:
1.数据量15万,执行成功,耗时8.928s
2.数据量5万,执行成功,耗时2.994s
3.数据量码悔知1万,执行成功,耗时0.634s
可以看到Mysql的游标在处理大一点的数据量时还是比较乏力的,仅适合用于操作几百上千的小数据量。
9. typecho对于大数据负载能力如何比如1000万数据,有谁测试过吗
众所周知,java在处理数据量比较大的时候,加载到内存必然会导致内存溢出,而在一些数据处理中我们不得不去处理海量数据,在做数据处理中,我们常见的手段是分解,压缩,并行,临时文件等方法;
例如,我们要将数据库(不论是什么数据库)的数据导出到一个文件,一般是Excel
或文本格式的CSV;对于Excel来讲,对于POI和JXL的接口,你很多时候没有办法去控制内存什么时候向磁盘写入,很恶心,而且这些API在内存构
造的对象大小将比数据原有的大小要大很多倍数,所以你不得不去拆分Excel,还好,POI开始意识到这个问题,在3.8.4的版本后,开始提供
cache的行数,提供了SXSSFWorkbook的接口,可以设置在内存中的行数,不过可惜的是,他当你超过这个行数,每添加一行,它就将相对行数前
面的一行写入磁盘(如你设置2000行的话,当你写第20001行的时候,他会将第一行写入磁盘),其实这个时候他些的临时文件,以至于不消耗内存,不过
这样你会发现,刷磁盘的频率会非常高,我们的确不想这样,因为我们想让他达到一个范围一次性将数据刷如磁盘,比如一次刷1M之类的做法,可惜现在还没有这
种API,很痛苦,我自己做过测试,通过写小的Excel比使用目前提供刷磁盘的API来写大文件,效率要高一些,而且这样如果访问的人稍微多一些磁盘
IO可能会扛不住,因为IO资源是非常有限的,所以还是拆文件才是上策;而当我们写CSV,也就是文本类型的文件,我们很多时候是可以自己控制的,不过你
不要用CSV自己提供的API,也是不太可控的,CSV本身就是文本文件,你按照文本格式写入即可被CSV识别出来;如何写入呢?下面来说说。。。
在处理数据层面,如从数据库中读取数据,生成本地文件,写代码为了方便,我们未必要
1M怎么来处理,这个交给底层的驱动程序去拆分,对于我们的程序来讲我们认为它是连续写即可;我们比如想将一个1000W数据的数据库表,导出到文件;此
时,你要么进行分页,oracle当然用三层包装即可,mysql用limit,不过分页每次都会新的查询,而且随着翻页,会越来越慢,其实我们想拿到一
个句柄,然后向下游动,编译一部分数据(如10000行)将写文件一次(写文件细节不多说了,这个是最基本的),需要注意的时候每次buffer的数据,
在用outputstream写入的时候,最好flush一下,将缓冲区清空下;接下来,执行一个没有where条件的SQL,会不会将内存撑爆?是的,这个问题我们值得去思考下,通过API发现可以对SQL进行一些操作,例如,通过:PreparedStatement
statement =
connection.prepareStatement(sql),这是默认得到的预编译,还可以通过设置:PreparedStatement
statement = connection.prepareStatement(sql ,
ResultSet.TYPE_FORWARD_ONLY ,
ResultSet.CONCUR_READ_ONLY);
来设置游标的方式,以至于游标不是将数据直接cache到本地内存,然后通过设置statement.setFetchSize(200);设置游标每次遍历的大小;OK,这个其实我用过,oracle用了和没用没区别,因为oracle的jdbc
API默认就是不会将数据cache到java的内存中的,而mysql里头设置根本无效,我上面说了一堆废话,呵呵,
我只是想说,java提供的标准API也未必有效,很多时候要看厂商的实现机制,还有这个设置是很多网上说有效的,但是这纯属抄袭;对于oracle上面
说了不用关心,他本身就不是cache到内存,所以java内存不会导致什么问题,如果是mysql,首先必须使用5以上的版本,然后在连接参数上加上
useCursorFetch=true这个参数,至于游标大小可以通过连接参数上加上:defaultFetchSize=1000来设置,例如:
jdbc:mysql://xxx.xxx.xxx.xxx:3306/abc?zeroDateTimeBehavior=convertToNull&useCursorFetch=true&defaultFetchSize=1000
上次被这个问题纠结了很久(mysql的数据老导致程序内存膨胀,并行2个直接系统
就宕了),还去看了很多源码才发现奇迹竟然在这里,最后经过mysql文档的确认,然后进行测试,并行多个,而且数据量都是500W以上的,都不会导致内
存膨胀,GC一切正常,这个问题终于完结了。
我们再聊聊其他的,数据拆分和合并,当数据文件多的时候我们想合并,当文件太大想要
拆分,合并和拆分的过程也会遇到类似的问题,还好,这个在我们可控制的范围内,如果文件中的数据最终是可以组织的,那么在拆分和合并的时候,此时就不要按
照数据逻辑行数来做了,因为行数最终你需要解释数据本身来判定,但是只是做拆分是没有必要的,你需要的是做二进制处理,在这个二进制处理过程,你要注意
了,和平时read文件不要使用一样的方式,平时大多对一个文件读取只是用一次read操作,如果对于大文件内存肯定直接挂掉了,不用多说,你此时因该每
次读取一个可控范围的数据,read方法提供了重载的offset和length的范围,这个在循环过程中自己可以计算出来,写入大文件和上面一样,不要
读取到一定程序就要通过写入流flush到磁盘;其实对于小数据量的处理在现代的NIO技术的中也有用到,例如多个终端同时请求一个大文件下载,例如视频
下载吧,在常规的情况下,如果用java的容器来处理,一般会发生两种情况:
其一为内存溢出,因为每个请求都要加载一个文件大小的内存甚至于更多,因为java
包装的时候会产生很多其他的内存开销,如果使用二进制会产生得少一些,而且在经过输入输出流的过程中还会经历几次内存拷贝,当然如果有你类似nginx之
类的中间件,那么你可以通过send_file模式发送出去,但是如果你要用程序来处理的时候,内存除非你足够大,但是java内存再大也会有GC的时
候,如果你内存真的很大,GC的时候死定了,当然这个地方也可以考虑自己通过直接内存的调用和释放来实现,不过要求剩余的物理内存也足够大才行,那么足够
大是多大呢?这个不好说,要看文件本身的大小和访问的频率;
其二为假如内存足够大,无限制大,那么此时的限制就是线程,传统的IO模型是线程是
一个请求一个线程,这个线程从主线程从线程池中分配后,就开始工作,经过你的Context包装、Filter、拦截器、业务代码各个层次和业务逻辑、访
问数据库、访问文件、渲染结果等等,其实整个过程线程都是被挂住的,所以这部分资源非常有限,而且如果是大文件操作是属于IO密集型的操作,大量的CPU
时间是空余的,方法最直接当然是增加线程数来控制,当然内存足够大也有足够的空间来申请线程池,不过一般来讲一个进程的线程池一般会受到限制也不建议太多
的,而在有限的系统资源下,要提高性能,我们开始有了new
IO技术,也就是NIO技术,新版的里面又有了AIO技术,NIO只能算是异步IO,但是在中间读写过程仍然是阻塞的(也就是在真正的读写过程,但是不会
去关心中途的响应),还未做到真正的异步IO,在监听connect的时候他是不需要很多线程参与的,有单独的线程去处理,连接也又传统的socket变
成了selector,对于不需要进行数据处理的是无需分配线程处理的;而AIO通过了一种所谓的回调注册来完成,当然还需要OS的支持,当会掉的时候会
去分配线程,目前还不是很成熟,性能最多和NIO吃平,不过随着技术发展,AIO必然会超越NIO,目前谷歌V8虚拟机引擎所驱动的node.js就是类
似的模式,有关这种技术不是本文的说明重点;
将上面两者结合起来就是要解决大文件,还要并行度,最土的方法是将文件每次请求的大
小降低到一定程度,如8K(这个大小是经过测试后网络传输较为适宜的大小,本地读取文件并不需要这么小),如果再做深入一些,可以做一定程度的
cache,将多个请求的一样的文件,cache在内存或分布式缓存中,你不用将整个文件cache在内存中,将近期使用的cache几秒左右即可,或你
可以采用一些热点的算法来配合;类似迅雷下载的断点传送中(不过迅雷的网络协议不太一样),它在处理下载数据的时候未必是连续的,只要最终能合并即可,在
服务器端可以反过来,谁正好需要这块的数据,就给它就可以;才用NIO后,可以支持很大的连接和并发,本地通过NIO做socket连接测试,100个终
端同时请求一个线程的服务器,正常的WEB应用是第一个文件没有发送完成,第二个请求要么等待,要么超时,要么直接拒绝得不到连接,改成NIO后此时
100个请求都能连接上服务器端,服务端只需要1个线程来处理数据就可以,将很多数据传递给这些连接请求资源,每次读取一部分数据传递出去,不过可以计算
的是,在总体长连接传输过程中总体效率并不会提升,只是相对相应和所开销的内存得到量化控制,这就是技术的魅力,也许不要太多的算法,不过你得懂他。
类似的数据处理还有很多,有些时候还会将就效率问题,比如在HBase的文件拆分和
合并过程中,要不影响线上业务是比较难的事情,很多问题值得我们去研究场景,因为不同的场景有不同的方法去解决,但是大同小异,明白思想和方法,明白内存
和体系架构,明白你所面临的是沈阳的场景,只是细节上改变可以带来惊人的效果。
-
10. 在oracle中,大数据量情况下,merge是否比cursor 快啊目前我们存储过程都是用cursor,但很慢。。
看你的业务逻辑是抄否复杂.
如果简单的, 可以一句 merge 语句就处理掉的。
那么当然优先使用 merge 处理比较好。
假如业务逻辑很复杂, 一句 merge 语句无法处理。
迫不得已,只能使用 游标处理的。
可以尝试使用 BULK COLLECT
看看是否能有一些性能上面的提升
http://hi..com/wangqing999/blog/item/2ea041cc0d4606037e3e6f20.html