如何进行实验四 cache性能分析测试,为什么要考虑计算能力,内存,cache,计算规模

软件性能测试_百度百科
软件性能测试
本词条缺少名片图,补充相关内容使词条更完整,还能快速升级,赶紧来吧!
测试是在交替进行负荷和时常用的术语。理想的“软件性能测试”(和其他类型的测试)应在需求文档或质量保证、中定义。软件性能测试一般包括和。
为了验证系统是否达到用户提出的性能指标,同时发现系统中存在的性能瓶颈,起到优化系统的目的。
软件性能测试,英文是Performance Testing。
通常验证软件的性能在正常环境和系统条件下重复使用是否还能满足性能指标。或者执行同样任务时新版本不比旧版本慢。一般还检查系统记忆容量在运行程序时会不会流失(memory leak)。比如,验证程序保存一个巨大的文件新版本不比旧版本慢。
SEI负载测试计划过程
目标:产生一个清晰、好理解、可验证的负载测试计划
内容:关注6个区域:目标、用户、用例、生产环境、、测试场景
工具:IBM、HP、OpenSource工具都支持。需有文档配合
目标:快速识别性能瓶颈
内容:重点测试“吞吐量”指标,因为RBI认定80%的系统性能瓶颈由吞吐量造成。
按照网络、硬件、数据库、、代码的顺序自上而下分析性能
工具:IBM、HP、OpenSource工具都支持。需使用分析模块、根据Weblogic、Oracle区别有专门的工具实现RBI。
性能下降曲线分析法
目标:性能随着用户数的增加而出现下降趋势的曲线分析、查看性能下降的环境点与上下文。确定性能阀值。
内容:通过单用户区域、性能平坦区域、压力区域、性能拐点进行监控和分析。
工具:IBM、HP、OpenSource工具都支持。IBM报表功能更强。
HP(LoadRuner)性能分析法
特点:侧重于该厂商的性能分析方法、主要体现在需求收集、VU脚本。
对于互联网应用软件,性能是其质量的一个非常重要的组成部分。作为解决问题的重要手段,软件性能测试已经广为人们所熟悉,并受到很高的关注。一般而言,软件性能测试都是在项目的后期才开展,被测试的对象通常是已经具备一定稳定性的产品。而实际上,软件性能测试应贯穿于整个中,和一样,软件性能测试也分为几个阶段。
软件生命周期与软件性能测试
不论哪种,、设计、编码、测试和运行维护这几个阶段都是其中的基本要素,只是在不同的软件生命周期模型中可能迭代、合并、拆分或重组这几个阶段,在此不做过多的描述。与其他几个阶段相对应,测试从软件开发过程按阶段可以划分为:、、,在其他的书上可能还能见到诸如、等名词,但是前3种测试确实是最基本的测试活动,而其他的测试活动只是在某些软件开发过程中会发生。
值得注意的是,通常在谈论单元测试、集成测试和系统测试时,其实仅仅谈论的是不同阶段的;而当讨论测试时,绝大多数的情况是,一个已经开发完毕或基本开发完毕的软件,测试人员用一种或几种软件性能测试工具,以尽量模拟真实用户行为的方式对该软件进行并发操作,收集并比较不同场景的结果,然后对软件的性能进行分析,这个活动通常发生在系统测试阶段,甚至更往后的阶段,如运行维护阶段。
一直以来,软件性能测试跟、似乎都是绝缘的。可是它们真的应该是绝缘的吗?没有任何理由可以说明软件性能测试跟单元测试、集成测试无关,除非你认为“这太难了,我不会做”。
我把“响应时间”的概念确定为“对请求作出响应所需要的时间”,把响应时间作`为用户视角的的主要体现。响应时间划分为“呈现时间”和“系统响应时间”两个部分。
其中“呈现时间”取决于数据在被客户端收到响应数据后呈现页面所消耗的时间、而“响应时间”指J2EE从请求发出开始到客户端接受到数据所消耗的时间。软件性能测试一般不关注“呈现时间”,因为呈现时间很大程度上取决于客户端的表现。在这里我们没有使用很多软件性能测试定义中的概念——“系统响应时间”定义为“应用系统从请求发出开始到客户端接收到最后一个数据所消耗的时间”,没有使用这种标准的原因是,可以使用一些编程技巧在数据尚未完全接收完成时进行呈现来减少用户感受到的响应时间,对于HNDLZCGLXT的这个项目中,我们针对C/S系统采用前者标准,对于B/S我们依然采用后一种标准。
并发用户数
我把“”与“”进行区别对待,我的“并发用户数”的标准是:并发用户数取决于测试对象的目标业务场景,因此,在确定这个“并发用户数”前,必须(必要)先对用户的业务进行分解、分析出典型的业务场景(也就是用户最常使用、最关注的业务操作),然后基于场景采用某些方法(有多种计算并发用户数的数学模型与公式)获得“并发用户数”。
这样做的原因是:假设一个应用系统、最高峰有500人同时在线、但这500人却不是并发用户数、因为假设在一个时间点上、有50%的人在填写复杂的表格(填写表格动作对服务器没有任何负担、只有在“提交”动作的时候才会对构成压力)、有40%的人在不停的从一个页面跳转到另外一个页面(不停发出请求与回应、产生服务器压力)、还有10%的人挂在线上,没有任何操作在发呆:)(没有对服务器构成压力的动作)。因此只有那40%的人真正对服务器产生了压力,从这里例子可以看出、关心的是不但是业务并发用户数、还取决于业务逻辑、业务场景。因此我们需要本文第六部分测试文档4、5、6。
我把吞吐量定义为“单位时间内系统处理的客户请求的数量”,直接体现软件系统的性能承载能力,对于交互式应用系统来说、吞吐量反映的是服务器承受的压力、在容量规划的测试中、吞吐量是一个重要指标、它不但反映在、数据库上、更加体现在硬件上。我们在以下方面利用这个指标:
(1) 用来协助设计测试场景,衡量软件性能测试是否达到了预计的设计目标、比如J2EE应用系统的、数据库事务发生频率、事务发生次数。
(2) 用来协助分析性能瓶颈、参照本文第二部分总的RBI方法。
性能计数器
性能计数器式描述服务器或操作系统性能的一些数据指标、例如对WINDOWS来说使用内存数、、进程时间等都是常见的计数器。 [Page]
对于性能计数器这个指标来说、需要考虑到的不但有硬件计数器、web服务器计数器、Weblogic服务器计数器、Servlet性能计数器、EJB2的性能计数器、JSF性能计数器、JMS性能计数器。找到这些指标是使用性能计数器的第一步、关键是找到性能瓶颈、确定系统阀值、提供优化建议才是性能计数器使用的关键。性能计数器复杂而繁多、与代码上下文环境、系统配置情况、系统架构、开发方式、使用到的规范实现、工具、类库版本都有紧密的联系、在此不作赘述。
我把思考时间确定为“休眠时间”。从业务系统的角度来说,这个时间指的是用户在惊醒操作时、每个请求之间的时间间隔、从的角度来说、要真实的测试模拟用户操作、就必须在中让各个操作之间等待一段时间、体现在脚本上就是在操作之间放置一个Think的函数,体现为脚本中两个请求语句之间的间隔时间、不同的测试工具提供了不同的函数或方法来实现思考时间、比如HP LoadRuner和IBM Rational Performance Tester的方式就完全不同。
1、 测试是在完成之后进行。
2、 软件性能、方案一般与统一在一个文档里。
3、 应尽量与用户环境保持一致。
4、 软件性能测试一般使用测试工具和测试人员编制来完成,软件性能测试的环境应单独运行尽量避免与其他软件同时使用。
5、 软件性能测试的重点在于前期数据的设计与后期数据的分析。
6、 软件性能测试的用例主要涉及到整个系统架构的问题,所以测试用例一旦生成,改动一般不大,所以做软件性能测试的重复使用率一般比较高。(说明:当系统中出现的某个功能点需要修改,它一般只会影响到的设计用例,而对于测试,很少影响到软件性能测试的设计用例。但是如果某个功能有较大的修改,软件性能测试也应该进行重新测试。)
软件性能测试小Tips
1、 测试指标的来源:测试的依据是产品的需求规格说明书;如果用户没有提出性能指标则根据用户需求、测试设计人员的经验来设计各项测试指标。
2、 软件性能测试的目的:通过测试确认软件是否满足产品的性能需求,同时发现系统中存在的性能瓶颈,起到优化系统的目的。
3、 软件性能测试的指标:服务器的各项指标(CPU使用率、、硬盘占用率等)、的各项指标和软件的响应时间:
(1) 操作系统有关的指标:CPU平均利用率、内存平均占用率、硬盘占用率、I/O数量、网络时延
(2) 数据库有关的指标:I/Owait、Mem平均使用率、cpu平均使用率、在一次I/O操作中所读的最大BLOCKS数、Log的增长情况、数据库的访问速度、数据库能支持的最大用户数、数据库CACHE命中率、不同数据库参数下的性能情况、锁的处理
(3) 软件有关的指标:交易的平均响应时间(从接收请求到回复响应的时间)、每秒交易数量(单位时间里的执行次数)、对功能的调用、延迟
4、 查看性能指标的命令和方法:
vmstat:的统计(cpu/io)
iostat:设备的IO统计
netstat:信息统计
top:内存统计
cat /proc/meninfo:查看系统的总men大小
cat /proc/cpuinfo:查看系统总CPU大小
df –k:查看系统硬盘大小
举例说明:
(1)查看CPU使用情况的命令
每5秒刷新一次,最右侧有CPU的占用率的数据:$ vmstat 5
top 然后按Shift+P,按照进程处理器占用率排序:$ top
(2)查看内存使用情况的命令
用free命令查看内存占用情况:$ free
top 然后按Shift+M, 按照进程排序:$ topCUDA Kepler(1) Read-Only Cache特性解析及其性能对比测试_leetCode答题报告5道题(四)_Oracle 字符集的查看和修改 __脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
CUDA Kepler(1) Read-Only Cache特性解析及其性能对比测试
leetCode答题报告5道题(四)
Oracle 字符集的查看和修改
CUDA Kepler(1) Read-Only Cache特性解析及其性能对比测试
CUDA Kepler(一) Read-Only Cache特性解析及其性能对比测试Kepler 计算设备
Kepler是NVIDIA发布的第三代CUDA计算设备的代号,这一系列产品主要有两大类:GK104和GK110,没有记错的话,GK104的运算能力是3.0,而GK110则具备了完整的Kepler架构组件,计算能力为3.5。两种计算能力的硬件在体系结构上面有一些差异,这些差异可能会在这一系列文章的后续版本中进行详细地讲解。今天我们讨论的是计算能力3.5的GK110架构新引入的一项特性:Read-Only Cache,以及讨论这一新的内存特性与CUDA原有的costant
memory及global memory的差异。通过实际的例子,让我们一起来探索该如何使用这一新的特性。
Read-Only Data Cache
这一名词可以简单翻译为“只读数据缓存”,那么,它是什么呢?
Read-Only Data Cache是一种数据缓存技术,它允许用户使用GPU的纹理缓存流水线来读取Global Memory中的只读数据。前面的句子有点长,下面让我来详细地说明一下。首先,什么是GPU的纹理缓存流水线呢?其实细节我也不是很清楚,但是这并非核心,读者和我所需要了解的是,GPU在访问存储器时,对于不同的内存类型(global memory、constant memory、shared memory等等),它会使用不同的流水线来进行load/store操作,而缓存流水线就是这些流水线中的其中一种。因此,使用纹理缓存流水也就意味着它与正常的读取global
memory所使用的是不同的流水线,两者在理论上应该是可以并行的。其次,什么是Global Memory中的只读数据呢?这其实是笔者臆想出来的一个表达,实际情况是这样的,如果用户有部分存放在Global Memory上的数据在CUDA kernel函数运行的时候保持不变,这部分数据就可以称作Global Memory中的只读数据。
那么,这个“只读数据缓存”有什么作用呢?
我们知道,在访问Global Memory时,为了获得更好的性能,我们必须确保程序对Global Memory的访问是Coalesced的,什么是Coalesced?简单来说就是一个线程块在访问Global Memory时所需要遵循的内存对齐要求(这种对齐要求的详细讲解可能会在以后的系列文章中涉及)。如果不能保证这一对齐策略,那么程序的访存性能将会受到影响,具体有多少跟硬件与访问的特定上下文有关,这里就不展开了。这时候,假如我们需要访问的内存在运行期间是不变的,那么,我们便可以使用Read-Only
Data Cache!你问我为什么?因为纹理内存的访问特性就是无序访问,而Read-Only Data Cache正是为了这一访存方式所设计的!因此,在某些特定场合,理论上Read-Only Data Cache将会带来意想不到的大幅度性能提升。
做一个总结吧,其实从Read-Only Data Cache使用纹理缓存流水就可以看出,NVIDIA的实际目的就是为了简化程序员对于纹理内存(Texture Memory)的使用,而实际上确实也是这样的,在3.5的硬件之前,要想使用访问纹理的方法访问Global Memory,需要做一些Texture Bind函数的调用工作,而这些工作不但非常繁琐,而且还具有使用上的限制(具体就不细讲了),有了这一新特性,纹理内存的使用被极大地简化了,是一个值得引起CUDA程序员重视的技术备选项。
Constant Memory
我想,作为一名CUDA程序员,Constant Memory的意义在这里无需赘述了,我下面想说的,是Constant Memory适宜的应用场合,而这个场合问题可能一直困扰着相当多的程序员(为什么我使用Constant Memory时性能总是比直接访问Global Memory慢?)。
首先,Constant Memory的特性:
1. Constant Memory是物理上存在的,它占据设备内存的一个64KB的空间。
2. 对于Constant Memory的访问是通过一个流水多处理器上的8KB的缓存来完成的。
3. Constant的设计初衷是用来向同一warp中的线程进行广播的。
下面,我们来详细讲述三种特性分别是什么以及它们对编程策略的影响:
第一项很直观,我们略过。
对于第二项,我想说明的是,流水多处理器对于Constant Memory的访问并不是直接的,而是通过了一层缓存(Cache)来进行,这一缓存的细节目前笔者也不是很了解,只知道它的大小是8KB。另外,对于一个CUDA程序,它最多只能使用64KB的Constant Memory,多了会出错(可能程序将无法运行?我没有测试过,因为我从来没有用到过那么多Constant Memory)。
第三项非常重要!“广播”意味着同一warp中的所有线程都能在一个时钟周期内收到某一特定地址的Constant Memory值。然后呢?请注意,“广播”同时也意味着如果在同一时刻同一warp中的线程访问的是Constant Memory中的不同位置的话,那么由于一个时钟周期只能广播一个值,所以这样的访存模型将会消耗多个时钟周期!明白了没?如果你对某个Constant Memory的访问是这样的:xx = yy[threadIdx.x],其中yy代表Constant
Memory,那么它的性能可能和你所预想的性能差别很大!
Global Memory
Global Memory暂时就不多讲了,列出来的原因是对它的访问也作为了测试比较的对照之一。Global Memory访问需要注意的一点是要保证访问是Coalesced的。
三种内存访问的性能比较
1. Global Memory
首先来看一看测试中我们需要用到的数据的声明:
__device__ double gpu_tab_W[6][6*6] =
{ 1.0/48.0,
-6.0/48.0,
12.0/48.0,
-8.0/48.0,
23.0/48.0, -30.0/48.0, -12.0/48.0,
24.0/48.0,
23.0/48.0,
30.0/48.0, -12.0/48.0, -24.0/48.0,
12.0/48.0,
8.0/48.0},
1.0/3840.0,
-10.0/3840.0,
40.0/3840.0,
-80.0/3840.0,
80.0/3840.0,
-32.0/3840.0,
237.0/3840.0,
-750.0/3840.0,
840.0/3840.0,
-240.0/3840.0,
-240.0/3840.0,
160.0/3840.0,
0.0, -0.0, -880.0/3840.0,
160.0/3840.0, -320.0/3840.0,
0.0, -880.0/3840.0,
160.0/3840.0,
320.0/3840.0,
237.0/3840.0,
750.0/3840.0,
840.0/3840.0,
240.0/3840.0,
-240.0/3840.0, -160.0/3840.0,
1.0/3840.0,
10.0/3840.0,
40.0/3840.0,
80.0/3840.0,
80.0/3840.0,
32.0/3840.0}
__constant__ double gpu_tab_W_c[6][6*6] =
{ 1.0/48.0,
-6.0/48.0,
12.0/48.0,
-8.0/48.0,
23.0/48.0, -30.0/48.0, -12.0/48.0,
24.0/48.0,
23.0/48.0,
30.0/48.0, -12.0/48.0, -24.0/48.0,
12.0/48.0,
8.0/48.0},
1.0/3840.0,
-10.0/3840.0,
40.0/3840.0,
-80.0/3840.0,
80.0/3840.0,
-32.0/3840.0,
237.0/3840.0,
-750.0/3840.0,
840.0/3840.0,
-240.0/3840.0,
-240.0/3840.0,
160.0/3840.0,
0.0, -0.0, -880.0/3840.0,
160.0/3840.0, -320.0/3840.0,
0.0, -880.0/3840.0,
160.0/3840.0,
320.0/3840.0,
237.0/3840.0,
750.0/3840.0,
840.0/3840.0,
240.0/3840.0,
-240.0/3840.0, -160.0/3840.0,
1.0/3840.0,
10.0/3840.0,
40.0/3840.0,
80.0/3840.0,
80.0/3840.0,
32.0/3840.0}
};哈哈,先不要感到头晕,其实上面的数据可以简单分为两类:
1、使用__device__关键字声明的存储在Global Memory中的数据。
2、使用__constant__关键字声明的存储在Constant Memory中的数据。
明白了这个,那么下面让我们看看如何操作它们。
首先来看程序,该程序是笔者从目前实际工程中的程序中抽离出来的一小段代码,我们来看看用哪种访存特性会更好:
__global__ void
kel_global_P (int np, int idx, double *out)
__shared__ double buffer[GPU_THREADS][2][HARD_CODED_LDP];
= threadIdx.x + blockIdx.x * blockDim.x;
= blockDim.x * gridDim.x;
double *p1
= buffer[threadIdx.x][0];
double *q1
= buffer[threadIdx.x][1];
double sum
double *tab = gpu_tab_W[5];
for (int i = i & i += tn) {
p1[0] = 1.0;
for (int x = 1; x & ++x)
p1[x] = sin((double)x * i * p1[x-1]);
for (int x = 0; x & ++x) {
q1[x] = 0.0;
for (int y = 0; y & ++y)
q1[x] += tab[i % 36] * p1[y];
for (int x = 0; x & ++x)
sum += q1[x];
下面我们来简单讲解一下,在这段代码中,核心的代码是对于tab的访问,程序第11行将tab赋值为gpu_tab_W[5],然后在程序的第21行访问它,这时各个线程将会对Global Memory进行访存操作。其它部分的代码读者可以不用管,因为它们对性能对比没有影响。2. Constant Memory
同样的功能让我们来看看用Constant Memory该如何访问呢:
__global__ void
kel_constant_P (int np, int idx, double *out)
__shared__ double buffer[GPU_THREADS][2][HARD_CODED_LDP];
= threadIdx.x + blockIdx.x * blockDim.x;
= blockDim.x * gridDim.x;
double *p1
= buffer[threadIdx.x][0];
double *q1
= buffer[threadIdx.x][1];
double sum
for (int i = i & i += tn) {
p1[0] = 1.0;
for (int x = 1; x & ++x)
p1[x] = sin((double)x * i * p1[x-1]);
for (int x = 0; x & ++x) {
q1[x] = 0.0;
for (int y = 0; y & ++y)
q1[x] += gpu_tab_W_c[5][i % 36] * p1[y];
for (int x = 0; x & ++x)
sum += q1[x];
}请注意,这一次,在程序的第20行,我们使用gpu_tab_W_c[5][i % 36]来直接访问Constant Memory。可以看出,对于同一warp中的不同线程,它们在同一时刻访问的并非同一Constant Memory地址,因此可以预见,理论上这种访存方式将会带来性能损失。
3. Read-Only Data Cache
想要使用Read-Only Data Cache需要符合某些条件,它必要的(但不是充分的)条件是在内存地址前加上__restrict__限定符,但是这样也不能完全保证程序执行时会真正使用Read-Only Data Cache,原因是编译器可能由于程序过于复杂而无法判断该引用的内存是否在运行期间是只读的。要保证使用Read-Only Data Cache,我们可以选择使用CUDA提供的__ldg()内建函数,具体的使用方法请看代码:
__global__ void
kel_read_only_P (const double* __restrict__ tab, int np, int idx,
double *out)
__shared__ double buffer[GPU_THREADS][2][HARD_CODED_LDP];
= threadIdx.x + blockIdx.x * blockDim.x;
= blockDim.x * gridDim.x;
double *p1
= buffer[threadIdx.x][0];
double *q1
= buffer[threadIdx.x][1];
double sum
for (int i = i & i += tn) {
p1[0] = 1.0;
for (int x = 1; x & ++x)
p1[x] = sin((double)x * i * p1[x-1]);
for (int x = 0; x & ++x) {
q1[x] = 0.0;
for (int y = 0; y & ++y)
q1[x] += __ldg(&tab[i % 36]) * p1[y];
for (int x = 0; x & ++x)
sum += q1[x];
从程序的20行可以看到,我们使用__ldg()来强制程序在此时使用Read-Only Data Cache,而在程序的第2行,细心的读者可以发现,在double*后面多了一个__restrict__限定符。没错,这两处就是想要使用Read-Only Data Cache在Kernel函数中所需要的所有改变。
有读者可能会问,你这个tab是从哪里得到的呢?是不是直接将gpu_tab_W加上一个偏移值传入的呢?很遗憾,不是,要想把使用__device__限定符声明的数组作为指针传入,还有一些额外的事情需要读者去做:你需要使用cudaGetSymbolAddress()函数来获取数组在设备端的地址。
好了,现在让我们来看看三个函数的运行结果,我们用nvprof来测试它们的运行时间:
如我们所料,Read-Only Data Cache在这种无序访问的访存模型中性能更好,而Constant Memory在此时性能明显较弱。但是,等等,为什么Global Memory的运行时间反而更少?这笔者只能说真的不知道!或许是数据量太少?或许是访存正好符合对齐规则?我暂时没有详细研究,不过聪明的读者是否可以深入分析一下呢?
到这个时候,如果你还能跟上我的思路,那么,我们将进入最后的一项测试:Constant Memory广播测试。如何测?其实很简单,你只需要将以上代码中所有的:
[i % 36]修改为:
[x * idx + y]这本来是需要一点篇幅来解释的,但是呢笔者还是相信聪明的读者在这一点上应该可以一眼看出来原因,由于笔者实在是饿了,赶着吃饭,因此就不赘述啦~哈哈。下面给出修改后的代码的nvprof运行结果:
可以看到,这一次Constant Memory反败为胜了~什么?为什么Global Memory又赢了?笔者也不知道啊!只能感叹太神奇了!
最后,列一下本次实验所使用的环境吧:
GPU:NVIDIA Tesla K20m
CUDA version: 5.5
欢迎读者来信讨论!
leetCode答题报告5道题(四)
leetCode解题报告5道题(四)题目一:
Longest Consecutive Sequence
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example,
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its
length: 4.
Your algorithm should run in O(n) complexity.
题意:给你一个数组,让你求出最大的连续序列的长度,我们的第一反应肯定都是排序,但是看到它最后一句话的要求“你的算法比较复杂度是O(n)的”,但是我一直不敢确定我的算法的复杂度是O(n),但是AC过了,如果没记错HashMap是基于红黑树的吧?那么它的插入应该是O(lgN),这样的话我这个算法应该复杂度是O(NlogN),如果你在这题上有自己的见解,希望可以给我留言,让我也学习一下!
分析:居然这个题目要我们求的是最大连续序列的长度,有重复的数字怎么办?又考虑到算法的效率,我们采用HashMap来存储对应的数字,重复的数字就不会被存储下来了,首先我们初始化Map集合,以数组中的值作为key, 所有的value都初始化为1
要查询一个数的最大连续序列,其实无非就是循环它的左侧,再循环它的右侧,两边去查找,直到值不存在于Map集合中,这时候这个数还有它的左右两边的那些数所能组成的最大连续序列就确定了,因此它左右侧的值也可以不用再求解了(Map中的value置为-1表示不需要求解的值。),如果这步漏了会出现TLE哦!!
Longest Consecutive Sequence
import java.util.HashM
import java.util.M
* @Description:
[求最大连续序列长度]
* @Author:
* @CreateDate:
[ 下午3:12:21]
* @CsdnUrl:
[http://blog.csdn.net/ljphhj]
public class Solution {
Map&Integer,Integer& map = new HashMap&Integer,Integer&();
public int longestConsecutive(int[] num) {
if (num.length == 0)
/*初始化Map集合*/
for (int i=0; i&num. ++i){
map.put(num[i], 1);
return findMaxNum(num);
public int findMaxNum(int[] arrays){
int max = Integer.MIN_VALUE;
/*判断数组中的所有元素*/
for (int i=0; i&arrays. ++i){
int sum = 0;
int key = arrays[i]; //取出对应的值(即map中的key)
//如果这个key还没有被求解过
if (map.get(key) != -1){
map.put(key, -1); //置为已求解过
/*求左右两侧*/
int left = key - 1;
int right = key + 1;
while (map.containsKey(left) && map.get(left) != -1){
map.put(left, -1);
left = left - 1;
while (map.containsKey(right) && map.get(right) != -1){
map.put(right, -1);
right = right + 1;
if (sum & max){
Valid Palindrome
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
For example,"A man, a plan, a canal: Panama" is a palindrome."race a car" is not a palindrome.
Have you consider that the string might be empty? This is a good question to ask during an interview.
For the purpose of this problem, we define empty string as valid palindrome.
分析:这题是判断给定字符串是否是回文串的,要我们只考虑字母和数字哈,其他的字符都当成不存在就可以了。还有字母的话忽略大小写。
个人觉得这就是考ASCII码表吧!
我们只要两个下标一个从左往右(leftIndex) , 一个从右往左(rightIndex), 如果当前遇到的是非字母或者数字的字符的话,对应下标做增(leftIndex)或者减(rightIndex), 直到leftIndex & rightIndex就结束了整个字符串的所有字符的访问。
java中,如果你要判断一个字符是字母或者数字可以用这个函数:Character.isLetterOrDigit(char c)
以下代码,为了凸显ASCII码,我不用java自带的这个函数哈!
ASCII码表图:
Valid Palindrome
public class Solution {
public boolean isPalindrome(String s) {
int len = s.length();
if (len == 0)
/*初始化左右两个下标*/
int leftIndex = 0;
int rightIndex = len-1;
/*迭代, 结束的条件是leftIndex & rightIndex 表示整个字符串的字符都访问过了*/
while (rightIndex &= leftIndex){
/*得到当前左右下标各自指向的字符的ASCII码*/
int leftInt = (int)(s.charAt(leftIndex));
int rightInt = (int)(s.charAt(rightIndex));
/*如果左下标指向的字符不属于数字或者字母,下标往后移*/
if (( !(65 &= leftInt && leftInt &= 90)
&& !(97 &= leftInt && leftInt &= 122)
&& !(48 &= leftInt && leftInt &= 57) )){
leftIndex++;
/*如果右下标指向的字符不属于数字或者字母,下标往前移*/
if (( !(65 &= rightInt && rightInt&= 90)
&& !(97 &= rightInt && rightInt&= 122)
&& !(48 &= rightInt && rightInt &= 57) )){
rightIndex--;
/*判断条件,字母的话忽略大小写*/
if( (rightInt == leftInt)
|| Math.abs(rightInt - leftInt) == 32 ){
leftIndex++;
rightIndex--;
Binary Tree Maximum Path Sum
Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
For example:
Given the below binary tree,
分析:题目给我们一颗二叉树,要求我们在二叉树中要选出一个结点(start)到另一个结点(end),使得这条路径上的所有结点的值加起来达到最大。
情况图解(只画出几种情况,其他的都类似):
由上这些情况,我们规定Null结点的值为Interget.MIN_VALUE(无穷小)
情况1: 代表的是左子树的值已经可以比左子树+根结点的值 还有 右子树+根结点的值来得大了,这时候这条路径就可以作为最大值的路径了
情况2: 子树中的某个区域构成的路径大于整个二叉树的其他路径总和
情况3: 二叉树的左右两边+根结点的值是最大值
情况4:二叉树中只有一个结点(无论值是正,负)都只能是最大值
情况5:最大值过根结点
ps:为了方便大家看几种情况数,才画了这么多个情况,实际上1,2,3种情况就够了哈!
解题思路: 这题主要是情况有很多种,一定要每种情况都分析到,不然的话,写代码很容易出错.
下面让我们来分析下解题的思路:
1、Null结点对应的值为无穷小(Interget.MIN_VALUE),保证情况4的成立
2、每个子树里面都有可能“左+根+右”的值大于“左+根”或者“右加根”,则我们可以求出这个值(max),代表这个子树所能达到的最大值。这个值再跟现在已经得到的最大值做比较。
3、步骤2已经讲了每个子树都有一个最大值,如果这个最大值满足了最大值路径,那么赋值给当前最大值,否则的话,我们需要得到一个这棵子树过一边的最大值(即“root.val + 左子树的最大值” 或者 “root.val + 右子树的最大值” 或者 "root.val"),因为如果你这棵子树没办法构成最大值路径的话,那么只能由你的上一级树再去做操作了,但是如果你交给上一级树做操作,那么你就不能再同时经过左右两个子树了,你只能选择如果root.val +
leftsum & root.val (左+中 & 中) 并且 root.val + leftsum & root.val + rightsum (左+中 & 右)那么你就返回经过“左子树”和“根结点”的这条路径的值给上一级。
递归处理,最后就可以得到结果了,不知道有没有描述清楚,代码里面会注释的哈,看代码理解吧!!
Binary Tree Maximum Path Sum
* Definition for binary tree
* public class TreeNode {
TreeNode(int x) { val = }
public class Solution {
/*当前得到的最大值*/
private int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
solveSum(root);
return maxS
/*递归函数*/
public int solveSum(TreeNode root) {
/*如果为Null结点,返回无穷大*/
if (root == null)
return Integer.MIN_VALUE;
int max = 0;
int leftsum = solveSum(root.left);
int rightsum = solveSum(root.right);
int sumLeftRootRight = root.
/*下面是为了求出当前这个树中可能的最大路径(可能包括左+中+右)*/
if (leftsum & 0){
sumLeftRootRight +=
if (rightsum & 0){
sumLeftRootRight +=
//求出这个树中的最大路径值
max = leftsum & rightsum ? leftsum & sumLeftRootRight ? leftsum : sumLeftRootRight : rightsum & sumLeftRootRight ? rightsum : sumLeftRootR
//如果这个值大于当前最大值
if (max & maxSum){
//把经过根结点的一条最大值的路径返回给上一级
//注意:居然要给上一级,那么过这棵子树的根结点的路径的情况
//1. 就一个root结点就最大了
//2. 过了root结点,再过root.left子树的最大路径,最大
//3. 过了root结点,再过root.right子树的最大路径,最大
int rootMaxSum = root.
rootMaxSum += leftsum & rightsum ? leftsum & 0 ? leftsum : 0 : rightsum & 0 ? rightsum : 0;
return rootMaxS
Reverse Words in a String
Given an input string, reverse the string word by word.
For example,
Given s = "the sky is blue",
return "blue is sky the".
分析:题目给我们一个字符串,然后让我们把字符串里面的单词做一下颠倒,每个单词间用空格隔开,但是没有跟我们讲可能出现多少个空格。因此这个题目要考虑的主要是用例的情况
1、s == null
2、s == "" || s== " "
return "";
--& return "b a";
主要的几种情况分析出来之后,我们就知道,给我们的这个待处理的字符串,必须要前trim() 掉两旁的空格。
然后我们选择遍历这个字符串s,把相邻的空格去掉(因为相邻的空格,题目要求之后输出也只输出一个,不能多输出!)
这样子这题目,基本上已经很清楚要怎么做了,由于我用的是JAVA实现,所以我想谈及一下关于题目中用到的
知识点:String,StringBuffer,StringBuilder的区别?
相信大家看到过很多比较String和StringBuffer区别的文章,也明白这两者的区别,然而自从Java 5.0发布以后,我们的比较列表上将多出一个对象了,这就是StringBuilder类。String类是不可变类,任何对String的改变都会引发新的String对象的生成;而StringBuffer则是可变类,任何对它所指代的字符串的改变都不会产生新的对象,可变和不可变类这一对对象已经齐全了,那么为什么还要引入新的StringBuilder类干吗?
如果你读过《Think in Java》,而且对里面描述HashTable和HashMap区别的那部分章节比较熟悉的话,你一定也明白了原因所在。对,就是支持线程同步保证线程安全而导致性能下降的问题。HashTable是线程安全的,很多方法都是synchronized方法,而HashMap不是线程安全的,但其在单线程程序中的性能比HashTable要高。StringBuffer和StringBuilder类的区别也在于此,新引入的StringBuilder类不是线程安全的,但其在单线程中的性能比StringBuffer高。
public class Solution {
public String reverseWords(String s) {
if (s == null || s.equals("")){
StringBuffer buffer = new StringBuffer();
s = s.trim();//取出两边的空格
/*把相邻的空格去除掉*/
for (int i=0; i&s.length(); ++i){
if (s.charAt(i) == ' ' && buffer.toString().charAt(buffer.toString().length()-1) == ' '){
buffer.append(s.charAt(i));
/*存储逆序的字符串*/
StringBuilder reverseStr = new StringBuilder("");
/*根据空格来做分割*/
String[] arrays = buffer.toString().split(" ");
for (int i=arrays.length-1; i&=0; --i){
if (!reverseStr.toString().equals("")){
reverseStr.append(" ");
reverseStr.append(arrays[i]);
return reverseStr.toString();
Unique Binary Search Trees II
(这个题目的姐妹题:Unique Binary Search Trees I的题解) http://blog.csdn.net/ljphhj/article/details/
Given n, generate all structurally unique BST's (binary search trees) that store values 1...n.
For example,
Given n = 3, your program should return all 5 unique BST's shown below.
confused what "{1,#,2,3}" means? &
read more on how binary tree is serialized on OJ.
分析:题目给我们一个数字n, 要让我们求出从 1....n的这些数字所能构成的BST(二叉搜索树)的情况,把这些情况构成的二叉树的结构作为返回值返回!
我们知道,数字n,它能构成的二叉搜索树的情况无外乎为下面几种
当rootValue = 1, 则 左子树 :null
右子树为:2 ~~ n 的组合(递归一下)
当rootValue = 3, 则 左子树 :1 ~~ 2 的组合
右子树为: 4 ~~ n的组合
当rootValue = n, 则 左子树 :1 ~~ n-1的组合
右子树为:null
这样,我们知道,如果要找出一个数字n的所有二叉搜索树的情况,那么就是要考虑到 根结点分别为:1 ~~ n的情况,然后每种情况下的
左右子树也还是一个组合, 比如当根结点值为i 的时候,左子树的情况有m种, 右子树的情况有k种,那么根结点值为 i 时,所能构成的二叉搜索树的总数就是 m * k种。
有了这个思路之后,我们直接看代码理解吧!!
import java.util.ArrayL
class TreeNode {
TreeNode(int x) {
* @Description:
[leetcode : Unique Binary Search Trees II ]
* @Author:
* @CreateDate:
[ 上午11:01:15]
* @CsdnUrl:
[http://blog.csdn.net/ljphhj]
public class Solution {
public ArrayList&TreeNode& generateTrees(int n) {
ArrayList&TreeNode& result = new ArrayList&TreeNode&();
if (n == 0){
result.add(null);
result = generateTree(1,n);
/*生成left ~~ right的二叉搜索树的情况*/
public ArrayList&TreeNode& generateTree(int left, int right){
ArrayList&TreeNode& result = new ArrayList&TreeNode&();
if (right & left){
result.add(null);
/*遍历root值分别为 left ~~ right的情况*/
for (int rootvalue= rootvalue&= ++rootvalue){
/*把左,右子树各自可能的情况分别放在两个集合中.*/
ArrayList&TreeNode& leftResult = generateTree(left, rootvalue-1);
ArrayList&TreeNode& rightResult = generateTree(rootvalue+1, right);
/*两个集合的组合数为最后的结果*/
for (int j=0; j&leftResult.size(); ++j){
for (int k=0; k&rightResult.size(); ++k){
TreeNode rootNode = new TreeNode(rootvalue);
rootNode.left = leftResult.get(j);
rootNode.right = rightResult.get(k);
result.add(rootNode);
public static void main(String[] args) {
Solution s = new Solution();
ArrayList&TreeNode& list = s.generateTrees(4);
Oracle 字符集的查看和修改
Oracle 字符集的查看和修改 .
Oracle 字符集的查看和修改 .一、什么是Oracle字符集
Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容关系。ORACLE 支持国家语言的体系结构允许你使用本地化语言来存储,处理,检索数据。它使数据库工具,错误消息,排序次序,日期,时间,货币,数字,和日历自动适应本地化语言和平台。 影响Oracle数据库字符集最重要的参数是NLS_LANG参数。它的格式如下: NLS_LANG = language_territory.charset 它有三个组成部分(语言、地域和字符集),每个成分控制了NLS子集的特性。其中: Language: 指定服务器消息的语言, 影响提示信息是中文还是英文Territory: 指定服务器的日期和数字格式,Charset:
指定字符集。如:AMERICAN _ AMERICA. ZHS16GBK 从NLS_LANG的组成我们可以看出,真正影响数据库字符集的其实是第三部分。所以两个数据库之间的字符集只要第三部分一样就可以相互导入导出数据,前面影响的只是提示信息是中文还是英文。二.字符集的相关知识:2.1 字符集
实质就是按照一定的字符编码方案,对一组特定的符号,分别赋予不同数值编码的集合。Oracle数据库最早支持的编码方案是US7ASCII。
Oracle的字符集命名遵循以下命名规则:
&Language&&bit size&&encoding&
即: &语言&&比特位数&&编码&
比如: ZHS16GBK表示采用GBK编码格式、16位(两个字节)简体中文字符集
2.2 字符编码方案2.2.1 单字节编码
(1)单字节7位字符集,可以定义128个字符,最常用的字符集为US7ASCII
(2)单字节8位字符集,可以定义256个字符,适合于欧洲大部分国家
例如:WE8ISO8859P1(西欧、8位、ISO标准8859P1编码) 2.2.2 多字节编码
(1)变长多字节编码
某些字符用一个字节表示,其它字符用两个或多个字符表示,变长多字节编码常用于对亚洲语言的支持,
例如日语、汉语、印地语等
例如:AL32UTF8(其中AL代表ALL,指适用于所有语言)、zhs16cgb231280
(2)定长多字节编码
每一个字符都使用固定长度字节的编码方案,目前oracle唯一支持的定长多字节编码是AF16UTF16,也是仅用于国家字符集 2.2.3 unicode编码
Unicode是一个涵盖了目前全世界使用的所有已知字符的单一编码方案,也就是说Unicode为每一个字符提供唯一的编码。UTF-16是unicode的16位编码方式,是一种定长多字节编码,用2个字节表示一个unicode字符,AF16UTF16是UTF-16编码字符集。
UTF-8是unicode的8位编码方式,是一种变长多字节编码,这种编码可以用1、2、3个字节表示一个unicode字符,AL32UTF8,UTF8、UTFE是UTF-8编码字符集
2.3 字符集超级
当一种字符集(字符集A)的编码数值包含所有另一种字符集(字符集B)的编码数值,并且两种字符集相同编码数值代表相同的字符时,则字符集A是字符集B的超级,或称字符集B是字符集A的子集。
Oracle8i和oracle9i官方文档资料中备有子集-超级对照表(subset-superset pairs),例如:WE8ISO8859P1是WE8MSWIN1252的子集。由于US7ASCII是最早的Oracle数据库编码格式,因此有许多字符集是US7ASCII的超集,例如WE8ISO8859P1、ZHS16CGB231280、ZHS16GBK都是US7ASCII的超集。
2.4 数据库字符集(oracle服务器端字符集)
数据库字符集在创建数据库时指定,在创建后通常不能更改。在创建数据库时,可以指定字符集(CHARACTER SET)和国家字符集(NATIONAL CHARACTER SET)。 2.4.1字符集
(1)用来存储CHAR, VARCHAR2, CLOB, LONG等类型数据
(2)用来标示诸如表名、列名以及PL/SQL变量等
(3)用来存储SQL和PL/SQL程序单元等 2.4.2国家字符集:
(1)用以存储NCHAR, NVARCHAR2, NCLOB等类型数据
(2)国家字符集实质上是为oracle选择的附加字符集,主要作用是为了增强oracle的字符处理能力,因为NCHAR数据类型可以提供对亚洲使用定长多字节编码的支持,而数据库字符集则不能。国家字符集在oracle9i中进行了重新定义,只能在unicode编码中的AF16UTF16和UTF8中选择,默认值是AF16UTF16 2.4.3查询字符集参数
可以查询以下数据字典或视图查看字符集设置情况
nls_database_parameters、props$、v$nls_parameters
查询结果中NLS_CHARACTERSET表示字符集,NLS_NCHAR_CHARACTERSET表示国家字符集 2.4.4修改数据库字符集
按照上文所说,数据库字符集在创建后原则上不能更改。不过有2种方法可行。1. 如果需要修改字符集,通常需要导出数据库数据,重建数据库,再导入数据库数据的方式来转换。2. 通过ALTER DATABASE CHARACTER SET语句修改字符集,但创建数据库后修改字符集是有限制的,只有新的字符集是当前字符集的超集时才能修改数据库字符集,例如UTF8是US7ASCII的超集,修改数据库字符集可使用ALTER DATABASE CHARACTER SET UTF8。
2.5 客户端字符集(NLS_LANG参数)2.5.1客户端字符集含义
客户端字符集定义了客户端字符数据的编码方式,任何发自或发往客户端的字符数据均使用客户端定义的字符集编码,客户端可以看作是能与数据库直接连接的各种应用,例如sqlplus,exp/imp等。客户端字符集是通过设置NLS_LANG参数来设定的。 2.5.2 NLS_LANG参数格式
NLS_LANG=&language&_&territory&.&client character set&
Language: 显示oracle消息,校验,日期命名
Territory:指定默认日期、数字、货币等格式
Client character set:指定客户端将使用的字符集
例如:NLS_LANG=AMERICAN_AMERICA.US7ASCII
AMERICAN是语言,AMERICA是地区,US7ASCII是客户端字符集 2.5.3客户端字符集设置方法
1)UNIX环境
$NLS_LANG=“simplified chinese”_china.zhs16gbk
$export NLS_LANG
编辑oracle用户的profile文件
2)Windows环境
编辑注册表
Regedit.exe ---》 HKEY_LOCAL_MACHINE ---》SOFTWARE ---》 ORACLE-HOME2.5.4 NLS参数查询
Oracle提供若干NLS参数定制数据库和用户机以适应本地格式,例如有NLS_LANGUAGE,NLS_DATE_FORMAT,NLS_CALENDER等,可以通过查询以下数据字典或v$视图查看。NLS_DATABASE_PARAMETERS:显示数据库当前NLS参数取值,包括数据库字符集取值NLS_SESSION_PARAMETERS:
显示由NLS_LANG 设置的参数,或经过alter session 改变后的参数值(不包括由NLS_LANG 设置的客户端字符集)NLS_INSTANCE_PARAMETE: 显示由参数文件init&SID&.ora 定义的参数V$NLS_PARAMETERS:显示数据库当前NLS参数取值 2.5.5修改NLS参数
使用下列方法可以修改NLS参数
(1)修改实例启动时使用的初始化参数文件
(2)修改环境变量NLS_LANG
(3)使用ALTER SESSION语句,在oracle会话中修改
(4)使用某些SQL函数
NLS作用优先级别:Sql function & alter session & 环境变量或注册表 & 参数文件 & 数据库默认参数 三.EXP/IMP 与 字符集3.1 EXP/IMP
Export 和 Import 是一对读写Oracle数据的工具。Export 将 Oracle 数据库中的数据输出到操作系统文件中, Import 把这些文件中的数据读到Oracle 数据库中,由于使用exp/imp进行数据迁移时,数据从源数据库到目标数据库的过程中有四个环节涉及到字符集,如果这四个环节的字符集不一致,将会发生字符集转换。 EXP
____________ _________________ _____________
|imp导入文件|&-|环境变量NLS_LANG|&-|数据库字符集|
------------
-----------------
------------- IMP
____________ _________________ _____________
|imp导入文件|-&|环境变量NLS_LANG|-&|数据库字符集|
------------
-----------------
------------- 四个字符集是
(1)源数据库字符集
(2)Export过程中用户会话字符集(通过NLS_LANG设定)
(3)Import过程中用户会话字符集(通过NLS_LANG设定)
(4)目标数据库字符集
3.2导出的转换过程
在Export过程中,如果源数据库字符集与Export用户会话字符集不一致,会发生字符集转换,并在导出文件的头部几个字节中存储Export用户会话字符集的ID号。在这个转换过程中可能发生数据的丢失。例:如果源数据库使用ZHS16GBK,而Export用户会话字符集使用US7ASCII,由于ZHS16GBK是16位字符集,而US7ASCII是7位字符集,这个转换过程中,中文字符在US7ASCII中不能够找到对等的字符,所以所有中文字符都会丢失而变成“?? ”形式,这样转换后生成的Dmp文件已经发生了数据丢失。因此如果想正确导出源数据库数据,则Export过程中用户会话字符集应等于源数据库字符集或是源数据库字符集的超集
3.3导入的转换过程
(1)确定导出数据库字符集环境
通过读取导出文件头,可以获得导出文件的字符集设置
(2)确定导入session的字符集,即导入Session使用的NLS_LANG环境变量
(3)IMP读取导出文件
读取导出文件字符集ID,和导入进程的NLS_LANG进行比较
(4)如果导出文件字符集和导入Session字符集相同,那么在这一步骤内就不需要转换,
如果不同,就需要把数据转换为导入Session使用的字符集。可以看出,导入数据到数据库过程中发生两次字符集转换
第一次:导入文件字符集与导入Session使用的字符集之间的转换,如果这个转换过程不能正确完成,Import向目标数据库的导入过程也就不能完成。
第二次:导入Session字符集与数据库字符集之间的转换。四. 查看数据库字符集涉及三方面的字符集,1. oracel server端的字符集;2. oracle client端的字符集;3. dmp文件的字符集。在做数据导入的时候,需要这三个字符集都一致才能正确导入。4.1 查询oracle server端的字符集 有很多种方法可以查出oracle server端的字符集,比较直观的查询方法是以下这种:SQL& select userenv('language')USERENV('LANGUAGE')----------------------------------------------------SIMPLIFIED CHINESE_CHINA.ZHS16GBKSQL&select userenv(‘language’) AMERICAN _ AMERICA. ZHS16GBK 4.2 如何查询dmp文件的字符集 用oracle的exp工具导出的dmp文件也包含了字符集信息,dmp文件的第2和第3个字节记录了dmp文件的字符集。如果dmp文件不大,比如只有几M或几十M,可以用UltraEdit打开(16进制方式),看第2第3个字节的内容,如0354,然后用以下SQL查出它对应的字符集: SQL& select nls_charset_name(to_number('0354','xxxx')) ZHS16GBK 如果dmp文件很大,比如有2G以上(这也是最常见的情况),用文本编辑器打开很慢或者完全打不开,可以用以下命令(在unix主机上): cat exp.dmp |od -x|head -1|awk '{print $2 $3}'|cut -c 3-6 然后用上述SQL也可以得到它对应的字符集。4.3 查询oracle client端的字符集 在windows平台下,就是注册表里面相应OracleHome的NLS_LANG。还可以在dos窗口里面自己设置,比如: set nls_lang=AMERICAN_AMERICA.ZHS16GBK 这样就只影响这个窗口里面的环境变量。 在unix平台下,就是环境变量NLS_LANG。 $echo $NLS_LANG AMERICAN_AMERICA.ZHS16GBK 如果检查的结果发现server端与client端字符集不一致,请统一修改为同server端相同的字符集。补充:(1).数据库服务器字符集select * from nls_database_parameters来源于props$,是表示数据库的字符集。(2).客户端字符集环境select * from nls_instance_parameters其来源于v$parameter,表示客户端的字符集的设置,可能是参数文件,环境变量或者是注册表(3).会话字符集环境select * from nls_session_parameters来源于v$nls_parameters,表示会话自己的设置,可能是会话的环境变量或者是alter session完成,如果会话没有特殊的设置,将与nls_instance_parameters一致。(4).客户端的字符集要求与服务器一致,才能正确显示数据库的非Ascii字符。如果多个设置存在的时候,NLS作用优先级别:Sql function & alter session & 环境变量或注册表 & 参数文件 & 数据库默认参数字符集要求一致,但是语言设置却可以不同,语言设置建议用英文。如字符集是zhs16gbk,则nls_lang可以是American_America.zhs16gbk。五. 修改oracle的字符集 按照上文所说,数据库字符集在创建后原则上不能更改。因此,在设计和安装之初考虑使用哪一种字符集十分重要。对数据库server而言,错误的修改字符集将会导致很多不可测的后果,可能会严重影响数据库的正常运行,所以在修改之前一定要确认两种字符集是否存在子集和超集的关系。一般来说,除非万不得已,我们不建议修改oracle数据库server端的字符集。特别说明,我们最常用的两种字符集ZHS16GBK和ZHS16CGB231280之间不存在子集和超集关系,因此理论上讲这两种字符集之间的相互转换不受支持。 不过修改字符集有2种方法可行。1. 通常需要导出数据库数据,重建数据库,再导入数据库数据的方式来转换。2. 通过ALTER DATABASE CHARACTER SET语句修改字符集,但创建数据库后修改字符集是有限制的,只有新的字符集是当前字符集的超集时才能修改数据库字符集,例如UTF8是US7ASCII的超集,修改数据库字符集可使用ALTER DATABASE CHARACTER SET UTF8。 5.1 修改server端字符集(不建议使用) 1.
关闭数据库SQL&SHUTDOWN IMMEDIATE2. 启动到MountSQL&STARTUP MOUNT; SQL&ALTER SYSTEM ENABLE RESTRICTED SESSION; SQL&ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0; SQL&ALTER SYSTEM SET AQ_TM_PROCESSES=0; SQL&ALTER DATABASE OPEN; --这里可以从父集到子集SQL&ALTER DATABASE CHARACTER SET ZHS16GBK; SQL&ALTER DATABASE NATIONAL CHARACTER SET ZHS16GBK; --如果是从子集到父集,需要使用INTERNAL_USE 参数,跳过超子集检测SQL&ALTER DATABASE CHARACTER SET INTERNAL_USE AL32UTF8; SQL&ALTER DATABASE NATIONAL CHARACTER SET INTERNAL_USE AL32UTF8;SQL&SHUTDOWN IMMEDIATE; SQL&STARTUP注意:如果没有大对象,在使用过程中进行语言转换没有什么影响,(切记设定的字符集必须是ORACLE支持,不然不能start) 按上面的做法就可以。若出现‘ORA-12717: Cannot ALTER DATABASE NATIONAL CHARACTER SET when NCLOB data exists’ 这样的提示信息,要解决这个问题有两种方法1. 利用INTERNAL_USE 关键字修改区域设置,2. 利用re-create,但是re-create有点复杂,所以请用internal_useSQL&SHUTDOWN IMMEDIATE;SQL&STARTUP MOUNT EXCLUSIVE;SQL&ALTER SYSTEM ENABLE RESTRICTED SESSION;SQL&ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;SQL&ALTER SYSTEM SET AQ_TM_PROCESSES=0;SQL&ALTER DATABASE OPEN;SQL&ALTER DATABASE NATIONAL CHARACTER SET INTERNAL_USE UTF8;SQL&SHUTDOWNSQL&如果按上面的做法做,National charset的区域设置就没有问题5.2 修改dmp文件字符集 上文说过,dmp文件的第2第3字节记录了字符集信息,因此直接修改dmp文件的第2第3字节的内容就可以‘骗’过oracle的检查。这样做理论上也仅是从子集到超集可以修改,但很多情况下在没有子集和超集关系的情况下也可以修改,我们常用的一些字符集,如US7ASCII,WE8ISO8859P1,ZHS16CGB231280,ZHS16GBK基本都可以改。因为改的只是dmp文件,所以影响不大。 具体的修改方法比较多,最简单的就是直接用UltraEdit修改dmp文件的第2和第3个字节。比如想将dmp文件的字符集改为ZHS16GBK,可以用以下SQL查出该种字符集对应的16进制代码: SQL& select to_char(nls_charset_id('ZHS16GBK'), 'xxxx') 0354 然后将dmp文件的2、3字节修改为0354即可。 如果dmp文件很大,用ue无法打开,就需要用程序的方法了。5.3客户端字符集设置方法
1)UNIX环境
$NLS_LANG=“simplified chinese”_china.zhs16gbk
$export NLS_LANG
编辑oracle用户的profile文件
2)Windows环境
编辑注册表
Regedit.exe ---》 HKEY_LOCAL_MACHINE ---》SOFTWARE ---》 ORACLE-HOME
或者在窗口设置:
set nls_lang=AMERICAN_AMERICA.ZHS16GBK 原文地址http://blog.csdn.net/tianlesoftware/article/details/4915223
如果您想提高自己的技术水平,欢迎加入本站官方1号QQ群:&&,&&2号QQ群:,在群里结识技术精英和交流技术^_^
本站联系邮箱:}

我要回帖

更多关于 千万级规模高性能 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信