随笔-314  评论-209  文章-0  trackbacks-0
 
 

早起的国内互联网都使用GBK编码,久之,所有项目都以GBK来编码了。对于J2EE项目,为了减少编码的干扰通常都是设置一个编码的Filter,强制将Request/Response编码改为GBK。例如一个Spring的常见配置如下:

 

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>GBK</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

毫无疑问,这在GBK编码的页面访问、提交数据时是没有乱码问题的。但是遇到Ajax就不一样了。Ajax强制将中文内容进行UTF-8编码,这样导致进入后端后使用GBK进行解码时发生乱码。网上的所谓的终极解决方案都是扯淡或者过于复杂,例如下面的文章:

这样的文章很多,显然:

  • 使用VB进行UTF-8转换成GBK提交是完全不可行(多浏览器、多平台完全不可用)
  • 使用复杂的js函数进行一次、多次编码,后端进行一次、多次解码也是不靠谱的,成本太高,无法重复使用

如果提交数据的时候能够告诉后端传输的编码信息是否就可以避免这种问题?比如Ajax请求告诉后端是UTF-8,其它请求告诉后端是GBK,这样后端分别根据指定的编码进行解码是不是就解决问题了。

有两个问题:

  1. 如何通过Ajax告诉后端的编码?Header过于复杂,Cookie成本太高,使用参数最方便。
  2. 后端何时进行解码?每一个请求进行解码,过于繁琐;获取参数时解码,此时已经乱码;在Filter里面动态设置编码是最完善的方案。
  3. 如何从参数中获取编码?如果是POST的body显然无法获取,因此在获取之前所有参数就已经按照某种编码解码过了,无法还原。所以通过URL传递编码最有效。支持GET/POST,同时成本很低。

解决了上述问题,来看具体实现方案。 列一段Java代码:

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.ClassUtils;
import org.springframework.web.filter.OncePerRequestFilter;

/** 自定义编码过滤器
 * @author imxylz (imxylz#gmail.com)
 * @sine 2011-6-9
 */
public class MutilCharacterEncodingFilter extends OncePerRequestFilter {

    static final Pattern inputPattern = Pattern.compile(".*_input_encode=([\\w-]+).*");

    static final Pattern outputPattern = Pattern.compile(".*_output_encode=([\\w-]+).*");

    // Determine whether the Servlet 2.4 HttpServletResponse.setCharacterEncoding(String)
    // method is available, for use in the "doFilterInternal" implementation.
    private final static boolean responseSetCharacterEncodingAvailable = ClassUtils.hasMethod(HttpServletResponse.class,
          "setCharacterEncoding", new Class[] { String.class });

    private String encoding;

    private boolean forceEncoding = false;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
 throws ServletException, IOException {
        String url = request.getQueryString();
        Matcher m = null;
        if (url != null && (m = inputPattern.matcher(url)).matches()) {//输入编码
            String inputEncoding = m.group(1);
            request.setCharacterEncoding(inputEncoding);
            m = outputPattern.matcher(url);
            if (m.matches()) {//输出编码
                response.setCharacterEncoding(m.group(1));
            } else {
                if (this.forceEncoding && responseSetCharacterEncodingAvailable) {
                    response.setCharacterEncoding(this.encoding);
                }
            }
        } else {
            if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
                request.setCharacterEncoding(this.encoding);
                if (this.forceEncoding && responseSetCharacterEncodingAvailable) {
                    response.setCharacterEncoding(this.encoding);
                }
            }
        }
        filterChain.doFilter(request, response);
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public void setForceEncoding(boolean forceEncoding) {
        this.forceEncoding = forceEncoding;
    }
}

解释下:

  • 如果URL的QueryString中包含_input_encode就使用此编码进行设置Request编码,以后参数按照此编码进行解析,例如如果是Ajax就传入UTF-8,如果是普通的GBK请求则无视此参数。
  • 如果无视此参数,则按照web.xml中配置的编码规则进行反编码,如果是GBK就按照GBK规则解析。
  • 对于输出编码同样使用上述规则。需要输出编码依赖输入编码,也就是说如果有一个_output_encode的输出编码,则同时需要有一个_input_encode编码来指定输入编码。当然你可以改造成不依赖输入编码。
  • 完全兼容Spring的org.springframework.web.filter.CharacterEncodingFilter编码规则,只需要替换类即可。
  • 没有继承org.springframework.web.filter.CharacterEncodingFilter类的原因是,org.springframework.web.filter.CharacterEncodingFilter里面的encoding参数和forceEncoding参数是private,子类无法使用。在有_input_encode而无_output_encode的时候想依然保持Spring的Response解析规则的话无法做到,所以将里面的代码拷贝过来使用。(为了展示方便,注释都删掉了)
  • 正则表达式可以改进成只需要匹配一次,从而可以提高一点点效率。
  • 所有后端请求将无视编码的存在,前端Ajax的GET/POST请求也将无视编码的存在,只是在URL地址中加上一个_input_encode=UTF-8的参数。仅此而已。
  • 如果想输出的编码也是UTF-8,比如手机端请求、跨站请求等,则需要URL地址参数_input_encode=UTF-8&_output_encode=UTF-8。
  • 对于POST请求,编码参数不能写在body里面,否则无法解析。
  • 显然,这种终极解决方案,在任何编码中都可以解决,GBK/UTF-8/ISO8859-1等编码任何组合都可以实现。
  • 唯一局限性是,此解决方案限制在J2EE项目中,其它平台不知是否有类似Filter这样的组件能够设置编码的概念。

posted @ 2011-06-21 11:54 xzc 阅读(2100) | 评论 (1)编辑 收藏
buffalo-2.0(国人开发的Ajax框架),下载buffalo-2.0-bin就可以了,个人认为也下载buffalo-2.0-src
下载地址:http://sourceforge.net/project/showfiles.php?group_id=178867

1.buffalo-2.0.jar
在buffalo-2.0-bin里,把它加到Web应用程序里的lib

2.buffalo.js和prototype.js
我把这两个文件放到Web应用程序的scripts/目录下,buffalo.js在buffalo-2.0-bin里,prototype.js在buffalo-demo.war里找

4.web.xml内容
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
    xmlns
="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation
="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
>
    
    
    
<servlet>
        
<servlet-name>bfapp</servlet-name>
        
<servlet-class>net.buffalo.web.servlet.ApplicationServlet</servlet-class>
    
</servlet>
    
<servlet-mapping>
        
<servlet-name>bfapp</servlet-name>
        
<url-pattern>/bfapp/*</url-pattern>
    
</servlet-mapping>
    
</web-app>


5.index.jsp文件
<%@ page language="java" pageEncoding="UTF-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  
<head>
    
<title>第一个 buffalo 示例程序</title>
    
<script language="JavaScript" src="scripts/prototype.js"></script>
    
<script language="JavaScript" src="scripts/buffalo.js"></script>
    
<script type="text/javascript">
    
var endPoint="<%=request.getContextPath()%>/bfapp";
    
    
var buffalo = new Buffalo(endPoint);
    
function hello(me) {
        buffalo.remoteCall(
"demoService.getHello", [me.value], function(reply) {
            alert(reply.getResult());
        })
    }
    
</script>
  
</head>
  
  
<body>
    输入你的名字:
<input type="text" name="myname">
    
<input type="button" value="Buffao远程调用" onclick="hello($('myname'));"><br>
  
</body>
</html>

说明:remoteCall是远程调用方法,demoService是buffalo-service.properties文件的键,getHello是被调用java类方法名,me.value是传给getHello方法的参数,reply.getResult()是getHello返回的值。

6.DemoService.java文件
package demo.buffalo;

/**
 * 
 * @文件名 demo.buffalo.DemoService.java
 * @作者 chenlb
 * @创建时间 2007-7-14 下午12:42:17 
 
*/
public class DemoService {

    
public String getHello(String name) {
        
return "Hello , "+name +" 这是第一个buffalo示例程序";
    }
}

7.buffalo-service.properties文件放到WEB-INF/classes/目录下
demoService=demo.buffalo.DemoService
说明:框架是通过此文件来查找远程调用的类的。

8.现在可以运行了。

示例下载
注意:Eclipse项目,文件编码是UTF-8

官方地址:
Buffalo中文论坛:http://groups.google.com/group/amowa
http://buffalo.sourceforge.net/tutorial.html

http://confluence.redsaga.com/pages/viewpage.action?pageId=1643

JavaScript API :http://confluence.redsaga.com/display/BUFFALO/JavaScript+API
http://www.amowa.net/buffalo/zh/index.html
posted @ 2011-06-16 16:44 xzc 阅读(377) | 评论 (0)编辑 收藏

转自:http://dingyu.me/blog/posts/view/flowchart-howtos

一个哥们在MSN上告诉我,他们公司的交互设计师只产出流程图,并问我用什么标准评价流程图的好坏。他的说法把我彻底震了-这分工也太细了吧!也不知道该说他们那里这样是好还是不好。

不过仔细想来,我倒的确没有仔细考虑过流程图的好坏,正好借此机会自我总结一下。

1、各司其职的形状

在我的流程图中,适用于不同目的和功能的形状都有各自确定的规范。到目前为止,我一共定义了以下一些形状:

(1)开始和结束

开始和结束

作为整张流程图的头和尾,必须标清楚到底具体指哪个页面,以免日后出现歧义。

(2)网页

网页

如你所见,网页的形状是一个带有漂亮的淡蓝色过渡效果的长方形,它的边框为深蓝色,中间写明了这个网页的用途,括号中的数字代表这个形状所对应的demo文件的名称(比如这里是2.html),我有时会把流程图输出为网页的形式,并把每个网页形状和它所对应的demo文件链接起来,这样查看起来非常方便。对OmniGraffle来说这是小菜一碟,如果你被迫用Visio,嗯……

另外,所有从形状出来的线条,都具有和此形状边框一样的颜色。这样的做法不仅看起来漂亮,在复杂的流程图中还能轻易地标明各形状的关系。我没有见过类似的做法,所以这是由我首创也说不定,呵。

(3)后台判断

后台判断

很常见的一个形状。我在用法上有一点和其他人的不同在于,我几乎总是让‘是’的分支往下流动,让‘否’的分支向右流动。因为流程图一般都是从上向下、从左到右绘制的,遵循上述规则一方面可以让绘制者不用为选择方向操心,另一方面也方便了读者阅读。

(4)表单错误页

表单错误页

既然有表单,当然会有错误信息。其实这个信息很重要,用户出错时惶恐不安,就靠着错误提示来解决问题了。你不在流程图里说什么时候显示错误页、不在demo里提供错误页,有些程序员会直接在网页上写个“错误,请检查”,所以UI设计师一定要对这个东西重视起来。

但一般来说也没必要把每种错误都在流程图中表示出来,因为含有两个文本框的表单就有三种出错情况了,多了就更不用说了。所以我都是把错误页变为表单的附属页,比如表单页的编号为2,那么此表单错误页的编号就从2.1开始排下去,每种错误放到一个附属页中,这样程序员在拿到demo时也能搞清楚什么意思。

结合网页和表单的形状,一个表单验证的流程图就是这样的:

表单验证的流程图

(5)后台动作

后台动作

并非所有后台动作都绘入流程图中(否则流程图就会变成庞然大物了),只有需要特别强调的后台动作(和用户体验直接相关的)才使用此形状。

(6)多重分支

多重分支

多重分支指的是几种并列的情况,每种情况都有发生的可能,发生哪种取决于分支起始处的判断结果。

(7)对话框

对话框

有时候一些操作可以利用对话框来完成, 这些对话框由js生成,显示在父界面之上。

(8)注释

注释

这个形状(比如页面)详细的内容,或者需要解释的业务逻辑,甚至用户此处的情况等,我都会放到注释中,这样既降低沟通成本,又可作为备忘。

(9)跳转点

跳转点

在一个复杂的流程图中,往往出现跳转到另外一个远处结点的情况,此时如果直接用线连过去,未免使得流程图显得凌乱,用一个跳转点就解决问题了。在点内标明跳转到的形状的编号,画起来容易,看起来也清楚。

此外,也可以利用跳转点来分割篇幅巨大的流程图,Yahoo!就这么用。

(10)子流程

子流程

分割篇幅巨大的流程图,更好的办法是用子流程。

要注意的是,如果你在流程图中使用了子流程这一形状,一定记得同时附上子流程图,以消除影响项目质量的不确定性因素。另外,在子流程图中也可以标明其所属关系。

(11)流程块

流程块

流程块使用示例

可以用流程块将整张流程图分隔为几个部分,并为每个部分单独命名(比如“流程块1”等)。这样做的目的在于从视觉上使复杂的流程图变得更为清晰,在沟通时也方便。

2、图例和流程图信息

图例和流程图信息

在团队合作中,图例是必须的,否则没人知道你画出来的东西到底是什么。即使流程图只给自己看,也最好养成标注图例的好习惯。其实这道理有点类似程序中的注释。

流程图信息也是必备的。其内容至少应包括作者、时间、流程图名称和版本(如下图)。这一方面可以让读者(其他同事)在有问题时能够方便地找到作者你,也起到了meta的作用。

3、绘制流程图的工具

Mac下首选OmniGraffle,Windows下除了Visio,似乎没有更好的选择(虽然Visio已经很难用了)。

4、评价流程图的好坏

我觉得一个好的流程图至少应做到以下几点:

  1. 密切地迎合了用户的心理状态、如实的反映了用户的操作习惯。流程图是要指导UI设计的,是UI设计的参照物,如果流程图本身无法正确描绘出用户的情况的话,UI十有八九会出问题;
  2. 覆盖了各种可能的情况和细节。这非常重要。任何在先期不确定的因素,都会在项目中成为随时引爆的地雷,都会直接降低最终上线的UI质量。此种情况真是屡见不鲜。但同时这条又很难做到,因为它不仅要求设计师熟悉用户,也要设计师充分知晓产品的商业逻辑,还要了解系统的运作机制,落下以上任何一个方面,都会在流程图中留下死角。这个问题我不知道有没有更好的解决方案,不过与PD和系分反复沟通是个行之有效的方法;
  3. 考虑到系统的设计和承受能力。系统的运作机制和承受能力必须在绘制流程图过程中考虑进去,以免出现流程图被开发人员枪毙的情况。我的习惯是,在绘制流程图时和系统分析师频繁沟通和交流,确保每一个环节都是可行的;
  4. 确保别人看得懂你的流程图。别人现在看不懂,你自己以后也一样看不懂。为了降低沟通成本,把流程图画清楚吧。

5、其它

(1)想办法把流程图绘制得漂亮些。谁不喜欢漂亮的东西呢?

这是我做过的一些流程图,当然文字全部模糊掉了(放图之前犹豫了好长时间-这样做不知是否有损我的职业道德。我特意请教了Fenng,他觉得没事。如果谁觉得有问题请直言不讳地告诉我)。

流程图示例1

流程图示例2

(2)如果你在公司里不是一锤定音式的人物的话,你就需要对你的文档进行版本管理。流程图也不例外,什么时间发布的什么版本,都要清楚地标出来,“ 最新”是个用不得的词。

 

我就说这么多了,抛砖引玉而已,蓉儿等人看你们的了!

噢对了,问个事儿:大家有没有觉得我每次写的文章都太长了?

 

posted @ 2011-05-27 17:07 xzc 阅读(686) | 评论 (1)编辑 收藏

从ftp定时下载按日期生成的文件

1、下载脚本get.bat如下

f:
cd f:/beifen (脚本所在目录)
set cicdate=%date:~0,4%%date:~5,2%%date:~8,2%
(echo open ftp地址
echo 用户名
echo 密码
echo prompt
echo get %cicdate%.txt
echo bye) > ftp_beifen.src

ftp -s:ftp_beifen.src
echo %date%导出数据库备份结束,时间:%time% >> getftp_beifen.log

2、在xp上定时自动运行批处理文件
  AT命令是Windows XP中内置的命令,它也可以媲美Windows中的“计划任务”,而且在计划的安排、任务的管理、工作事务的处理方面,
    AT命令具有更强大更神通的功能。AT命令可在指定时间和日期、在指定计算机上运行命令和程序。
   
    查看所有安排的计划   at
    取消已经安排的计划   at 5 /Delete
  
在dos下运行一下命令,系统就会在每天的16:46分自动运行批处理文件get.bat
net stop schedule
net start schedule
at 16:46 /every:Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday F:\beifen\get.bat

posted @ 2011-05-21 12:11 xzc 阅读(4674) | 评论 (1)编辑 收藏

转自:http://blog.csdn.net/tianlesoftware/archive/2009/12/01/4915223.aspx

一、什么是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-HOME

 

2.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') from dual;

USERENV('LANGUAGE')

----------------------------------------------------

SIMPLIFIED CHINESE_CHINA.ZHS16GBK

 

SQL>select userenv(‘language’) from dual;

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')) from dual;

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 IMMEDIATE

 

2. 启动到Mount

SQL>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;

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_use

 

SQL>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>SHUTDOWN immediate;

SQL>startup;

如果按上面的做法做,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') from dual;

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

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tianlesoftware/archive/2009/12/01/4915223.aspx

posted @ 2011-04-15 10:58 xzc 阅读(904) | 评论 (0)编辑 收藏
转自:http://blog.csdn.net/tianlesoftware/archive/2009/11/04/4764254.aspx

从10g开始,oracle开始提供Shrink的命令,假如我们的表空间中支持自动段空间管理 (ASSM),就可以使用这个特性缩小段,即降低HWM。这里需要强调一点,10g的这个新特性,仅对ASSM表空间有效,否则会报 ORA-10635: Invalid segment or tablespace type。

 

有关ASSM的详细信息,请参考我的Blog:Oracle 自动段空间管理

http://blog.csdn.net/tianlesoftware/archive/2009/12/07/4958989.aspx

 

如果经常在表上执行DML操作,会造成数据库块中数据分布稀疏,浪费大量空间。同时也会影响全表扫描的性能,因为全表扫描需要访问更多的数据块。从oracle10g开始,表可以通过shrink来重组数据使数据分布更紧密,同时降低HWM释放空闲数据块。

 

 

segment shrink分为两个阶段:

 

1、数据重组(compact):通过一系列insert、delete操作,将数据尽量排列在段的前面。在这个过程中需要在表上加RX锁,即只在需要移动的行上加锁。由于涉及到rowid的改变,需要enable row movement.同时要disable基于rowid的trigger.这一过程对业务影响比较小。

 

2、HWM调整:第二阶段是调整HWM位置,释放空闲数据块。此过程需要在表上加X锁,会造成表上的所有DML语句阻塞。在业务特别繁忙的系统上可能造成比较大的影响。

 

 

shrink space语句两个阶段都执行。

 

shrink space compact只执行第一个阶段。

如果系统业务比较繁忙,可以先执行shrink space compact重组数据,然后在业务不忙的时候再执行shrink space降低HWM释放空闲数据块。

 

shrink必须开启行迁移功能。

alter table table_name enable row movement ;

 

注意:alter table XXX enable row movement语句会造成引用表XXX的对象(如存储过程、包、视图等)变为无效。执行完成后,最好执行一下utlrp.sql来编译无效的对象。

 

 

语法:

alter table <table_name> shrink space [ <null> | compact | cascade ];

alter table <table_name> shrink space compcat;

收缩表,相当于把块中数据打结实了,但会保持 high water mark;

 

alter table <tablespace_name> shrink space;

收缩表,降低 high water mark;

 

alter table <tablespace_name> shrink space cascade;

收缩表,降低 high water mark,并且相关索引也要收缩一下下。

 

alter index idxname shrink space;

回缩索引

 

 

1:普通表

 

Sql脚本,改脚本会生成相应的语句

select'alter table '||table_name||' enable row movement;'||chr(10)||'alter table '||table_name||' shrink space;'||chr(10)from user_tables;

 

select'alter index '||index_name||' shrink space;'||chr(10)from user_indexes;

 

2:分区表的处理

 

进行shrink space时 发生ORA-10631错误.shrink space有一些限制.

 

在表上建有函数索引(包括全文索引)会失败。

 

Sql脚本,改脚本会生成相应的语句

 

select 'alter table '||table_name||' enable row movement;'||chr(10)||'alter table '||table_name||' shrink space;'||chr(10) from user_tables where ;

 

select 'alter index '||index_name||' shrink space;'||chr(10) from user_indexes where uniqueness='NONUNIQUE' ;

 

select 'alter table '||segment_name||' modify subpartition '||partition_name||' shrink space;'||chr(10) from user_segments where segment_type='TABLE SUBPARTITION' ';

 

 

详细测试:

 

我们用系统视图all_objects来在上个测试的tablespace ASSM上创建测试表my_objects

 

/* Formatted on 2009-12-7 20:42:45 (QP5 v5.115.810.9015) */

CREATE TABLESPACE ASSM DATAFILE 'd:\ASSM01.dbf' SIZE 100M EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;

 

/* Formatted on 2009-12-7 20:39:26 (QP5 v5.115.810.9015) */

SELECT   TABLESPACE_NAME,

         BLOCK_SIZE,

         EXTENT_MANAGEMENT,

         ALLOCATION_TYPE,

         SEGMENT_SPACE_MANAGEMENT

  FROM   dba_tablespaces

 WHERE   TABLESPACE_NAME = 'ASSM';

 

 

TABLESPACE_NAME         BLOCK_SIZE EXTENT_MAN ALLOCATIO SEGMEN

--------------------- ---------- ---------- --------- ------

ASSM                      8192         LOCAL       SYSTEM    AUTO 

1 row selected.

 

/* Formatted on 2009-12-7 20:44:15 (QP5 v5.115.810.9015) */

CREATE TABLE my_objects

TABLESPACE assm

AS

   SELECT   * FROM all_objects;

 

然后我们随机地从table MY_OBJECTS中删除一部分数据:

SQL> SELECT   COUNT ( * ) FROM my_objects;

COUNT(*)

----------

49477

SQL> delete from my_objects where object_name like '%C%';

SQL> delete from my_objects where object_name like '%U%';

SQL> delete from my_objects where object_name like '%A%';

 

现在我们使用show_space()来看看my_objects的数据存储状况:

注: show_space() 存储过程代码参看一下连接的附件

http://blog.csdn.net/tianlesoftware/archive/2009/12/07/4958989.aspx

 

SQL>exec show_space('my_objects','auto','T','Y');

Total Blocks............................768

Total Bytes.............................6291456

Unused Blocks...........................68

Unused Bytes............................557056

Last Used Ext FileId....................8

Last Used Ext BlockId...................649

Last Used Block.........................60

 *************************************************

The segment is analyzed

0% -- 25% free space blocks.............41

0% -- 25% free space bytes..............335872

25% -- 50% free space blocks............209

25% -- 50% free space bytes.............1712128

50% -- 75% free space blocks............190

50% -- 75% free space bytes.............1556480

75% -- 100% free space blocks...........229

75% -- 100% free space bytes............1875968

Unused Blocks...........................0

Unused Bytes............................0

Total Blocks............................11

Total bytes.............................90112

PL/SQL 过程已成功完成。

这里,table my_objects的HWM下有767个block,其中,free space为25-50%的block有209个,free space为50-75%的block有190个,free space为75-100%的block有229个. Total blocks 11个。

 

这种情况下,我们需要对这个table的现有数据行进行重组。

 

要使用assm上的shink,首先我们需要使该表支持行移动,可以用这样的命令来完成:

alter table my_objects enable row movement;

现在,就可以来降低my_objects的HWM,回收空间了,使用命令:

alter table bookings shrink space;

 

我们具体的看一下实验的结果:

SQL> alter table my_objects enable row movement;

表已更改。

SQL> alter table my_objects shrink space;

表已更改。

SQL>exec show_space('my_objects','auto','T','Y');

Total Blocks............................272

Total Bytes.............................2228224

Unused Blocks...........................0

Unused Bytes............................0

Last Used Ext FileId....................8

Last Used Ext BlockId...................265

Last Used Block.........................16

 *************************************************

The segment is analyzed

0% -- 25% free space blocks.............0

0% -- 25% free space bytes..............0

25% -- 50% free space blocks............0

25% -- 50% free space bytes.............0

50% -- 75% free space blocks............1

50% -- 75% free space bytes.............8192

75% -- 100% free space blocks...........0

75% -- 100% free space bytes............0

Unused Blocks...........................0

Unused Bytes............................0

Total Blocks............................257

Total bytes.............................2105344

 

在执行玩shrink命令后,我们可以看到,table my_objects的HWM现在降到了271的位置,而且HWM下的block的空间使用状况,Total blocks 的block有257个,free space 为25-50% Block只有0个。

 

 

Shrink 的实现机制:

我们接下来讨论一下shrink的实现机制,我们同样使用讨论move机制的那个实验来观察。

/* Formatted on 2009-12-7 20:58:40 (QP5 v5.115.810.9015) */

CREATE TABLE TEST_HWM (id  INT, name CHAR (2000))

TABLESPACE ASSM;

 

INSERT INTO TEST_HWM  VALUES   (1, 'aa');

INSERT INTO TEST_HWM  VALUES   (2, 'bb');

INSERT INTO TEST_HWM  VALUES   (2, 'cc');

INSERT INTO TEST_HWM VALUES   (3, 'dd');

INSERT INTO TEST_HWM VALUES   (4, 'ds');

INSERT INTO TEST_HWM VALUES   (5, 'dss');

INSERT INTO TEST_HWM VALUES   (6, 'dss');

INSERT INTO TEST_HWM VALUES   (7, 'ess');

INSERT INTO TEST_HWM VALUES   (8, 'es');

INSERT INTO TEST_HWM VALUES   (9, 'es');

INSERT INTO TEST_HWM VALUES   (10, 'es');

 

我们来看看这个table的rowid和block的ID和信息:

/* Formatted on 2009-12-7 21:00:02 (QP5 v5.115.810.9015) */

SQL>SELECT   ROWID, id, name FROM TEST_HWM;ROWID ID NAME

ROWID                       ID NAME

-------------------------------------    ---------- --------

AAANMEAAIAAAAEcAAA          3 dd

AAANMEAAIAAAAEcAAB          4 ds

AAANMEAAIAAAAEcAAC          5 dss

AAANMEAAIAAAAEdAAA          6 dss

AAANMEAAIAAAAEdAAB          7 ess

AAANMEAAIAAAAEdAAC          8 es

AAANMEAAIAAAAEeAAA          9 es

AAANMEAAIAAAAEeAAB         10 es

AAANMEAAIAAAAEgAAA          1 aa

AAANMEAAIAAAAEgAAB          2 bb

AAANMEAAIAAAAEgAAC          2 cc

 

/* Formatted on 2009-12-7 21:00:49 (QP5 v5.115.810.9015) */

SQL>SELECT   EXTENT_ID,

         FILE_ID,

         RELATIVE_FNO,

         BLOCK_ID,

         BLOCKS

  FROM   dba_extents

 WHERE   segment_name = 'TEST_HWM';

 

 EXTENT_ID    FILE_ID RELATIVE_FNO   BLOCK_ID     BLOCKS

---------- ---------- ------------ ---------- ----------

         0          8            8        281          8

1 row selected.

 

然后从table test_hwm中删除一些数据:

delete from TEST_HWM where id = 2;

delete from TEST_HWM where id = 4;

delete from TEST_HWM where id = 3;

delete from TEST_HWM where id = 7;

delete from TEST_HWM where id = 8;

 

观察table test_hwm的rowid和blockid的信息:

SQL> select rowid , id,name from TEST_HWM;

ROWID                          ID NAME

------------------------------------------ ---------- ---------

AAANMEAAIAAAAEcAAC          5 dss

AAANMEAAIAAAAEdAAA          6 dss

AAANMEAAIAAAAEeAAA          9 es

AAANMEAAIAAAAEeAAB         10 es

AAANMEAAIAAAAEgAAA          1 aa

 

/* Formatted on 2009-12-7 21:00:49 (QP5 v5.115.810.9015) */

SQL>SELECT   EXTENT_ID,

         FILE_ID,

         RELATIVE_FNO,

         BLOCK_ID,

         BLOCKS

  FROM   dba_extents

 WHERE   segment_name = 'TEST_HWM';

 

 EXTENT_ID    FILE_ID RELATIVE_FNO   BLOCK_ID     BLOCKS

---------- ---------- ------------ ---------- ----------

         0          8            8        281          8

1 row selected.

 

从以上的信息,我们可以看到,在table test_hwm中,剩下的数据是分布在AAAAEc,AAAAEd,AAAAEf,AAAAEg这样四个连续的block中。

 

SQL> exec show_space('TEST_HWM','auto','T','Y');

Total Blocks............................8

Total Bytes.............................65536

Unused Blocks...........................0

Unused Bytes............................0

Last Used Ext FileId....................8

Last Used Ext BlockId...................281

Last Used Block.........................8

 *************************************************

The segment is analyzed

0% -- 25% free space blocks.............0

0% -- 25% free space bytes..............0

25% -- 50% free space blocks............1

25% -- 50% free space bytes.............8192

50% -- 75% free space blocks............3

50% -- 75% free space bytes.............24576

75% -- 100% free space blocks...........1

75% -- 100% free space bytes............8192

Unused Blocks...........................0

Unused Bytes............................0

Total Blocks............................0

Total bytes.............................0

 

我们可以看到目前这四个block的空间使用状况,AAAAEc,AAAAEd,AAAAEf,AAAAEg上各有一行数据,我们猜测free space为50-75%的3个block是这三个block,那么free space为25-50%的1个block就是AAAAEg了,剩下free space为 75-100% 的3个block,是HWM下已格式化的尚未使用的block。(在extent不大于于16个block时,是以一个extent为单位来移动的)

 

然后,我们对table my_objects执行shtink的操作:

SQL> alter table test_hwm enable row movement;

Table altered

SQL> alter table test_hwm shrink space;

Table altered

SQL> select rowid ,id,name from TEST_HWM;

ROWID                      ID NAME

------------------ ---------- ------------

AAANMEAAIAAAAEcAAA         10 es

AAANMEAAIAAAAEcAAC          5 dss

AAANMEAAIAAAAEcAAD          1 aa

AAANMEAAIAAAAEcAAE          9 es

AAANMEAAIAAAAEdAAA          6 dss

 

/* Formatted on 2009-12-7 21:00:49 (QP5 v5.115.810.9015) */

SQL>SELECT   EXTENT_ID,

         FILE_ID,

         RELATIVE_FNO,

         BLOCK_ID,

         BLOCKS

  FROM   dba_extents

 WHERE   segment_name = 'TEST_HWM';

 

 EXTENT_ID    FILE_ID RELATIVE_FNO   BLOCK_ID     BLOCKS

---------- ---------- ------------ ---------- ----------

         0          8            8        281          8

1 row selected.

 

当执行了shrink操作后,有意思的现象出现了。我们来看看oracle是如何移动行数据的,这里的情况和move已经不太一样了。我们知道,在move操作的时候,所有行的rowid都发生了变化,table所位于的block的区域也发生了变化,但是所有行物理存储的顺序都没有发生变化,所以我们得到的结论是,oracle以block为单位,进行了block间的数据copy。那么shrink后,我们发现,部分行数据的rowid发生了变化,同时,部分行数据的物理存储的顺序也发生了变化,而table所位于的block的区域却没有变化,这就说明,shrink只移动了table其中一部分的行数据,来完成释放空间,而且,这个过程是在table当前所使用的block中完成的。

 

那么Oracle具体移动行数据的过程是怎样的呢?我们根据这样的实验结果,可以来猜测一下:

Oracle是以行为单位来移动数据的。Oracle从当前table存储的最后一行数据开始移动,从当前table最先使用的block开始搜索空间,所以,shrink之前,rownum=10的那行数据(10,es),被移动到block AAAAEc上,写到(1,aa)这行数据的后面,所以(10,es)的rownum和rowid同时发生改变。然后是(9,es)这行数据,重复上述过程。这是oracle从后向前移动行数据的大致遵循的规则,那么具体移动行数据的的算法是比较复杂的,包括向ASSM的table中insert数据使用block的顺序的算法也是比较复杂的,大家有兴趣的可以自己来研究,在这里我们不多做讨论。

 

在shrink table的同时shrink这个table上的index:

alter table my_objects shrink space cascade;

同样地,这个操作只有当table上的index也是ASSM时,才能使用。

 

 

Move 和 Shrink 产生日志的对比

我们对比了同样数据量和分布状况的两张table,在move和shrink下生成的redo size(table上没有index的情况下):

/* Formatted on 2009-12-7 21:20:43 (QP5 v5.115.810.9015) */

SQL>SELECT   tablespace_name, SEGMENT_SPACE_MANAGEMENT

  FROM   dba_tablespaces

 WHERE   tablespace_name IN ('ASSM', 'HWM');

 

TABLESPACE_NAME   SEGMENT_SPACE_MANAGEMENT

------------------------------  ------------------------

ASSM                  AUTO

HWM                  MANUAL

SQL> create table my_objects tablespace ASSM as select * from all_objects where rownum<20000;

Table created

SQL> create table my_objects1 tablespace HWM as select * from all_objects where rownum<20000;

Table created

SQL> select bytes/1024/1024 from user_segments where segment_name = 'MY_OBJECTS';

BYTES/1024/1024

---------------

2.1875

SQL> delete from my_objects where object_name like '%C%';

7278 rows deleted

SQL> delete from my_objects1 where object_name like '%C%';

7278 rows deleted

SQL> delete from my_objects where object_name like '%U%';

2732 rows deleted

SQL> delete from my_objects1 where object_name like '%U%';

2732 rows deleted

SQL> commit;

Commit complete

SQL> alter table my_objects enable row movement;

Table altered

/* Formatted on 2009-12-7 21:21:48 (QP5 v5.115.810.9015) */

SQL>SELECT   VALUE

  FROM   v$mystat, v$statname

 WHERE   v$mystat.statistic# = v$statname.statistic#

         AND v$statname.name = 'redo size';

VALUE

----------

27808792

SQL> alter table my_objects shrink space;

Table altered

SQL>SELECT   VALUE

  FROM   v$mystat, v$statname

 WHERE   v$mystat.statistic# = v$statname.statistic#

         AND v$statname.name = 'redo size';

VALUE

----------

32579712

SQL> alter table my_objects1 move;

Table altered

SQL>SELECT   VALUE

  FROM   v$mystat, v$statname

 WHERE   v$mystat.statistic# = v$statname.statistic#

         AND v$statname.name = 'redo size';

VALUE

----------

32676784

对于table my_objects,进行shrink,产生了32579712 – 27808792=4770920,约4.5M的redo ;对table my_objects1进行move,产生了32676784-32579712= 97072,约95K的redo size。

 

结论:与move比较起来,shrink的日志写要大得多。

 

 

Shrink的几点问题:

1.      shrink后index是否需要rebuild:

 

因为shrink的操作也会改变行数据的rowid,那么,如果table上有index时,shrink table后index会不会变为UNUSABLE呢?

我们来看这样的实验,同样构建my_objects的测试表:

create table my_objects tablespace ASSM as select * from all_objects where rownum<20000;

create index i_my_objects on my_objects (object_id);

delete from my_objects where object_name like '%C%';

delete from my_objects where object_name like '%U%';

现在我们来shrink table my_objects:

SQL> alter table my_objects enable row movement;

Table altered

SQL> alter table my_objects shrink space;

Table altered

SQL> select index_name,status from user_indexes where index_name='I_MY_OBJECTS';

INDEX_NAME STATUS

------------------------------ --------

I_MY_OBJECTS VALID

我们发现,table my_objects上的index的状态为VALID,估计shrink在移动行数据时,也一起维护了index上相应行的数据rowid的信息。我们认为,这是对于move操作后需要rebuild index的改进。但是如果一个table上的index数量较多,我们知道,维护index的成本是比较高的,shrink过程中用来维护index的成本也会比较高。

 

2. shrink时对table的lock

在对table进行shrink时,会对table进行怎样的锁定呢?当我们对table MY_OBJECTS进行shrink操作时,查询v$locked_objects视图可以发现,table MY_OBJECTS上加了row-X (SX) 的lock:

SQL>select OBJECT_ID, SESSION_ID,ORACLE_USERNAME,LOCKED_MODE from v$locked_objects;

OBJECT_ID SESSION_ID ORACLE_USERNAME LOCKED_MODE

---------- ---------- ------------------ -----------

55422 153 DLINGER 3

SQL> select object_id from user_objects where object_name = 'MY_OBJECTS';

OBJECT_ID

----------

55422

那么,当table在进行shrink时,我们对table是可以进行DML操作的。

 

3. shrink对空间的要求

我们在前面讨论了shrink的数据的移动机制,既然oracle是从后向前移动行数据,那么,shrink的操作就不会像move一样,shrink不需要使用额外的空闲空间。

 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tianlesoftware/archive/2009/11/04/4764254.aspx

posted @ 2011-04-15 10:57 xzc 阅读(9340) | 评论 (0)编辑 收藏

转自:http://blog.csdn.net/rein07/archive/2010/11/25/6033937.aspx

1.SQL>shutdown abort 如果数据库是打开状态,强行关闭

2.SQL>sqlplus / as sysdba

3.SQL>startup
ORACLE 例程已经启动。

Total System Global Area 293601280 bytes
Fixed Size 1248624 bytes
Variable Size 121635472 bytes
Database Buffers 167772160 bytes
Redo Buffers 2945024 bytes
数据库装载完毕。
ORA-01122: 数据库文件 1 验证失败
ORA-01110: 数据文件 1:
'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\SYSTEM01.DBF'
ORA-01207: 文件比控制文件更新 - 旧的控制文件

4.SQL>alter database backup controlfile to trace as 'f:\aa';
数据库已更改。

5.SQL>shutdown immediate 如果数据库是打开状态,则关闭
ORA-01109: 数据库未打开
已经卸载数据库

6.SQL>startup nomount;
ORACLE 例程已经启动。
Total System Global Area 105979576 bytes
Fixed Size 454328 bytes
Variable Size 79691776 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes

7.Editplus之类的编辑器打开在第四步生成的f:\aa文件;
其实在这个文件中的已经告诉你咋样恢复你的数据库了,找到STARTUP NOMOUNT字样,然后下面可以看到类似语句,这个文件有好几个类似的生成控制文件语句,主要针对不懂的环境执行不同的语句,象我的数据库没有做任何备份,也不是在归档模式,就执行这句
CREATE CONTROLFILE REUSE DATABASE "ORCLDW" NORESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 292
LOGFILE
GROUP 1 'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\REDO01.LOG' SIZE 50M,
GROUP 2 'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\REDO02.LOG' SIZE 50M,
GROUP 3 'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\REDO03.LOG' SIZE 50M
DATAFILE
'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\SYSTEM01.DBF',
'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\UNDOTBS01.DBF',
'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\SYSAUX01.DBF',
'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\USERS01.DBF',
'F:\ORACLE\PRODUCT\10.2.0\DB_1\ORADATA\ORCLDW\EXAMPLE01.DBF'
CHARACTER SET ZHS16GBK
;
执行上面这段语句,这个语句重建控制文件,然后你可以看着f:\aa文件完成下面的恢复工作了,

8.SQL>RECOVER DATABASE (恢复指定表空间、数据文件或整个数据库)

9.SQL>ALTER DATABASE OPEN 打开数据库

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/rein07/archive/2010/11/25/6033937.aspx

posted @ 2011-04-15 10:56 xzc 阅读(6986) | 评论 (0)编辑 收藏

引用

trailblizerOracle:Rank,Dense_Rank,Row_Number比较

Oracle:Rank,Dense_Rank,Row_Number比较

一个员工信息表

Create Table EmployeeInfo (CODE Number(3) Not Null,EmployeeName varchar2(15),DepartmentID Number(3),Salary NUMBER(7,2),

Constraint PK_EmployeeInfo Primary Key (CODE));

Select * From EMPLOYEEINFO

Oracle:Rank,Dense_Rank,Row_Number比较 - trailblizer - trailblizer的博客

现执行SQL语句:

Select EMPLOYEENAME,SALARY,

RANK() OVER (Order By SALARY Desc)  "RANK",

DENSE_RANK() OVER (Order By SALARY Desc ) "DENSE_RANK",

ROW_NUMBER() OVER(Order By SALARY Desc) "ROW_NUMBER"

 From EMPLOYEEINFO

结果如下:

Oracle:Rank,Dense_Rank,Row_Number比较 - trailblizer - trailblizer的博客

Rank,Dense_rank,Row_number函数为每条记录产生一个从1开始至N的自然数,N的值可能小于等于记录的总数。这3个函数的唯一区别在于当碰到相同数据时的排名策略。

①ROW_NUMBER:

Row_number函数返回一个唯一的值,当碰到相同数据时,排名按照记录集中记录的顺序依次递增。

②DENSE_RANK:

Dense_rank函数返回一个唯一的值,除非当碰到相同数据时,此时所有相同数据的排名都是一样的。

③RANK:

Rank函数返回一个唯一的值,除非遇到相同的数据时,此时所有相同数据的排名是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间空出排名。

同时也可以分组排序,也就是在Over从句内加入Partition by groupField:

 Select DEPARTMENTID,EMPLOYEENAME,SALARY,

RANK() OVER ( Partition By DEPARTMENTID Order By SALARY Desc)  "RANK",

DENSE_RANK() OVER ( Partition By DEPARTMENTID Order By SALARY Desc ) "DENSE_RANK",

ROW_NUMBER() OVER( Partition By DEPARTMENTID Order By SALARY Desc) "ROW_NUMBER"

 From EMPLOYEEINFO

结果如下:

Oracle:Rank,Dense_Rank,Row_Number比较 - trailblizer - trailblizer的博客

现在如果插入一条工资为空的记录,那么执行上述语句,结果如下:

Oracle:Rank,Dense_Rank,Row_Number比较 - trailblizer - trailblizer的博客

会发现空值的竟然排在了第一位,这显然不是想要的结果。解决的办法是在Over从句Order By后加上 NULLS Last即:

Select EMPLOYEENAME,SALARY,

RANK() OVER (Order By SALARY Desc  Nulls Last)  "RANK",

DENSE_RANK() OVER (Order By SALARY Desc Nulls Last) "DENSE_RANK",

ROW_NUMBER() OVER(Order By SALARY Desc Nulls Last ) "ROW_NUMBER"

 From EMPLOYEEINFO

结果如下:

Oracle:Rank,Dense_Rank,Row_Number比较 - trailblizer - trailblizer的博客

posted @ 2011-04-03 21:46 xzc 阅读(635) | 评论 (0)编辑 收藏

Oracle Sql Loader中文字符导入乱码的解决方案
服务器端字符集NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK

控制文件ctl:
LOAD DATA
CHARACTERSET ZHS16GBK
INFILE 'c:\testfile.txt'
id name desc

FIELDS TERMINATED BY ","
(id,name ,desc )

导入成功

其中c:\testfile.txt文件中有中文,在将此文件导入到oracle数据库中时,需要设置字符集CHARACTERSET ZHS16GBK
 
(1)查看服务器端字符集
通过客户端或服务器端的sql*plus登录ORACLE的一个合法用户,执行下列SQL语句:
SQL > select * from V$NLS_PARAMETERS
------------------------
(2)控制文件ctl:
LOAD DATA
CHARACTERSET ZHS16GBK
INFILE '/inffile/vac/subs-vac.csv'
TRUNCATE
INTO TABLE INF_VAC_SUBS_PRODUCT
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(
USER_NUMBER,
PRODUCT_ID,
EFFECTIVE_DATE DATE "YYYY/MM/DD HH24:MI:SS",
EXPIRATION_DATE DATE "YYYY/MM/DD HH24:MI:SS"
)

posted @ 2011-03-08 17:20 xzc 阅读(9059) | 评论 (2)编辑 收藏
文章分类:数据库

要测试sql loader 以及快速产生大量测试数据

生成大量测试数据思路。

  一,用plsql developer 生成csv 文件

  二,用>>输出重定向,追加到一个cvs 文件里。

  三,再用sql loader 快速载入。

 

在plsql developer 执行

Sql代码 复制代码
  1. SELECT object_id,object_name FROM dba_objects;  

 

右键plsql developer 导出csv 格式 1.csv。在linux 上执行下面的脚本

C代码 复制代码
  1. #!/bin/bash   
  2.   
  3. for((i=1;i<200;i=i+1))   
  4. do  
  5.         cat 1.csv >> 2.csv;   
  6.         echo $i;   
  7. done  

 这样 50000  *  200 差不到就有一千万的数据了。我测试的  11047500  392M

 可以用:

Linux代码 复制代码
  1. wc -l 2.csv  

 

查看csv 里有多少条数据。现在测试数据有了。我们来试一下sql loader 的载入效果吧。

创建sqlloader 控制文件如下,保存为1.ctl

Sqlldr ctl代码 复制代码
  1. load data   
  2. infile '2.csv'  
  3. into table my_objects   
  4. fields terminated by ','optionally enclosed by '"'  
  5. (object_id,   
  6. object_name   
  7. );  

 

控制文件简要说明:

-- INFILE 'n.csv'   导入多个文件 
-- INFILE *  要导入的内容就在control文件里 下面的BEGINDATA后面就是导入的内容

--BADFILE '1.bad'   指定坏文件地址 

--apend into table my_objects 追加
-- INSERT  装载空表 如果原先的表有数据 sqlloader会停止 默认值 
-- REPLACE   原先的表有数据 原先的数据会全部删除 
-- TRUNCATE  指定的内容和replace的相同 会用truncate语句删除现存数据 

--可以指定位置加载
--(object_id position(1:3) char,object_name position(5:7) char)
--分别指定分隔符
--(object_id char terminated by ",", object_name char terminated by ",")
--执行sqlldr userid=scott/a123 control=1.ctl log=1.out direct=true
--30秒可以载入200万的测试数据 79MB


--sqlldr userid=/ control=result1.ctl direct=true parallel=true
--sqlldr userid=/ control=result2.ctl direct=true parallel=true
--sqlldr userid=/ control=result2.ctl direct=true parallel=true
--当加载大量数据时(大约超过10GB),最好抑制日志的产生:
--SQLALTER TABLE RESULTXT nologging;
--这样不产生REDO LOG,可以提高效率。然后在CONTROL文件中load data上面加一行:unrecoverable
--此选项必须要与DIRECT共同应用。
--在并发操作时,ORACLE声称可以达到每小时处理100GB数据的能力!其实,估计能到1-10G就算不错了,开始可用结构
--相同的文件,但只有少量数据,成功后开始加载大量数据,这样可以避免时间的浪费

 

下面就是执行了

Shell代码 复制代码
  1. sqlldr userid=scott/a123 control=1.ctl log=1.out direct=true  

 结果:30秒可以载入200万的测试数据 79MB
          226秒载入1100万的测试数据 392Mb

 

我的环境是在虚拟机,测得的结果

MemTotal:       949948 kB

model name      : Intel(R) Pentium(R) D CPU 2.80GHz
stepping        : 8
cpu MHz         : 2799.560
cache size      : 1024 KB

 

还是挺快的:)

posted @ 2011-03-08 16:47 xzc 阅读(3992) | 评论 (0)编辑 收藏
仅列出标题
共32页: First 上一页 8 9 10 11 12 13 14 15 16 下一页 Last