<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Ordier</title>
    <description></description>
    <link>http://ordier.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>spring-MVC框架的一点认识</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/200854" style="color:red;">http://ordier.javaeye.com/blog/200854</a>&nbsp;
          发表时间: 2008年06月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          DispatchServlet 是一个Servlet 对所有匹配的url进行处理<br />对它进行配置的xml文件默认是 {servlet-name}-servlet.xml<br />这个文件中配置了spring的MVC框架。<br />DispatchServlet 接受到请求之后 <br />通过URL找到适合的处理器映射，使用处理器映射SimpleUrlHandlerMapping或者BeanNameUrlHandlerMapping <br />一个基本的HandlerMapping所提供的功能是将请求传递到HandlerExecutionChain上，首先HandlerExecutionChain包含一个符合输入请求的处理器。其次（但是可选的）是一个可以拦截请求的拦截器列表。当收到请求，DispatcherServlet将请求交给处理器映射，让它检查请求并获得一个正确的HandlerExecutionChain。然后，执行定义在执行链中的处理器和拦截器（如果有拦截器的话）<br /><br />Controller 的操作流程<br />对表单来说，spring标签让你把表单数据绑定到指定的对象上，该对象要自己来定义，但它不需要实现任何接口，然后在Controller 中从该对象中提取用户数据，在这之前可以先对表单数据进行验证，然后执行业务逻辑的方法，执行完之后，返回一个返回一个ModelAndView对象例如：<br />   ModelAndView("Cart", "cart", cart);<br />其中"Cart"为视图对象<br />由resolver 处理逻辑名找到对应真正的资源（jsp文件）<br />后面两个的实际操作是把它们放到一个map对象中，<br />name："cart" value：cart<br /><br /><br />BeanNameUrlHandlerMapping<br />它将收到的HTTP请求映射到在web应用上下文中定义的bean的名字上<br />SimpleUrlHandlerMapping<br />需要提供映射的url，和对应的controller<br />支持正则表达式的url<br /><br /><br />拦截器的概念：<br />处理器映射提供了拦截器概念，当你想要为所有请求提供某种功能时，例如做某种检查，这就非常有用。<br /><br />处理器映射中的拦截器必须实现org.springframework.web.servlet包中的HandlerInterceptor接口。这个接口定义了三个方法，一个在处理器执行前被调用，一个在处理器执行后被调用，另一个在整个请求处理完后调用。这三个方法提供你足够的灵活度做任何处理前和处理后的操作。<br /><br />preHandle方法有一个boolean返回值。使用这个值，你可以调整执行链的行为。当返回true时，处理器执行链将继续执行，当返回false时，DispatcherServlet认为拦截器本身将处理请求（比如显示正确的视图），而不继续执行执行链中的其它拦截器和处理器。<br /><br />简单的示例：webminimal<br />网址：http://www.jactiongroup.net/reference/html/mvc.html#mvc-handlermapping
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/200854#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 06 Jun 2008 11:59:22 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/200854</link>
        <guid>http://ordier.javaeye.com/blog/200854</guid>
      </item>
      <item>
        <title>spring aop 和java的动态代理</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/200853" style="color:red;">http://ordier.javaeye.com/blog/200853</a>&nbsp;
          发表时间: 2008年06月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          spring AOP 的实现是基于java的动态代理，其目的就是不改写原来代码来添加功能：<br /><br />代理接口：<br /><br />public interface User {<br /> <br /> public void save();<br /> public void test();<br /><br />}<br /><br />实现类：<br /><br />public class UserImpl implements User {<br /> <br /> public void save(){<br />  System.out.println("Method save invoke!!!");<br /> }<br /> <br /> public void test(){<br />  System.out.println("test method!!!1");<br /> }<br /><br />}<br /><br />代理对象：<br /><br />import java.lang.reflect.InvocationHandler;<br />import java.lang.reflect.*;<br /><br />public class UserProxy implements InvocationHandler {<br /> <br /> private Object obj;<br /><br /> <br /> public Object bind(Object obj){<br />  this.obj=obj;<br />  return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);<br /> }<br /> public Object invoke(Object proxy, Method method, Object[] args)<br />   throws Throwable {<br />  Object result = null;<br />  if (method.getName().equalsIgnoreCase("save")) {<br />   System.out.println("before invoke save method");<br />   result = method.invoke(obj, args);<br />   System.out.println("method invoke success!!!");<br />  } else {<br />   result = method.invoke(obj, args);<br />  }<br />  return result;<br /><br /> }<br /><br />}<br /><br />测试对象：<br />public class Tester {<br /><br /> public static void main(String[] args) {<br />  <br />  UserProxy userProxy= new UserProxy();<br />  User u =(User)userProxy.bind(new UserImpl());<br /><br />  u.save();<br />  u.test();<br /><br /> }<br />}
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/200853#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 06 Jun 2008 11:58:28 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/200853</link>
        <guid>http://ordier.javaeye.com/blog/200853</guid>
      </item>
      <item>
        <title>关于java中的对象序列化</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/200851" style="color:red;">http://ordier.javaeye.com/blog/200851</a>&nbsp;
          发表时间: 2008年06月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在用netbeans5.0 做GUI时，想要在用户每次登录时，上次的登录信息能够得到保存，当然可以把他们作为配置信息写入文件，每次程序启动时读取文件。但是java语言有更好的方法解决这个问题： Serializable接口<br /><br />java对象序列化机制一般来讲有两种用途： <br />    <br />    1.需要将对象的状态保存到文件中，而后能够通过读入对象状态来重新构造对象，恢复程序状态。 <br />    <br />    2.使用套接字在网络上传送对象的程序来说，是很有用的。 <br /><br />    我们通过让类实现java.io.Serializable 接口可以将类序列化。这个接口是一个制造者（marker）接口。也就是说，对于要实现它的类来说，该接口不需要实现任何方法。它主要用来通知Java虚拟机(JVM)，需要将一个对象序列化。 <br />    <br />    对于这个，有几点我们需要明确： <br />    <br />    1.并非所有类都可以序列化，在cmd下，我们输入serialver java.net.socket，可以得到socket是否可序列化的信息，实际上socket是不可序列化的。 <br />    <br />    2.java有很多基础类已经实现了serializable接口，比如string,vector等。但是比如hashtable就没有实现serializable接口。 <br />    <br />    将对象读出或者写入流的主要类有两个: ObjectOutputStream与ObjectInputStream 。ObjectOutputStream 提供用来将对象写入输出流的writeObject方法， ObjectInputStream提供从输入流中读出对象的readObject方法。使用这些方法的对象必须已经被序列化的。也就是说，必须已经实现Serializable接口。如果你想writeobject一个hashtable对象，那么，会得到一个异常。<br /><br />看到这里或许很多人都会有个疑问,是否所有的对象都可以序列化呢? <br />    <br />    当然是不可以的了,至于为什么不可以,那就有很多原因了,比如: <br />    <br />    1.安全方面的原因,比如 <br />一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的. <br />    <br />    2.资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现.
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/200851#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 06 Jun 2008 11:56:18 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/200851</link>
        <guid>http://ordier.javaeye.com/blog/200851</guid>
      </item>
      <item>
        <title>quartz 中JobExecutionContext的使用</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/158814" style="color:red;">http://ordier.javaeye.com/blog/158814</a>&nbsp;
          发表时间: 2008年01月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          假如execute方法中需要一些额外的数据怎么办？比如说execute<br /> 中希望发送一封邮件，但是我需要知道邮件的发送者、接收者等信息?<br /><br /> 存在两种解决方案：<br /><br />1.JobDataMap类：<br />   每个JobDetail都关联了一个JobDataMap实例，JobDataMap是java.util.Map的子类，基本上是提供key-value形式的数据，并提供了一些便利方法（主要是对java基本数据类型的支持，如put(String key,int value)），当开发人员创建JobDetail的时候，可以把附加信息放到JobDataMap中，那么在execute方法中可以根据key找到需要的值。<br />   JobDetail job = new JobDetail....<br />   job.getJobDataMap().put("from","snowway@vip.sina.com");<br />   ...   <br /><br />在execute中<br />   String from = jobExecutionContext.getJobDetail().getJobDataMap().getString("from");<br />   ....<br /><br />   不过，当你使用数据库存储JobDetail的时候（默认情况下使用RAM），这里有一个致命的弱点，你不能把没有实现java.io.Serializable的对象放入JobDataMap中，因为Quartz将使用Blob字段保存（也可以通过配置文件关闭）序列化过的JobDataMap中的对象。比如你在execute方法中需要一个java.sql.Connection接口实例，这种情况也是普遍的，那么通常情况下你不能把Connection放入JobDataMap，即使你只想在execute中使用。（注：读者可暂时认为上面这段话是正确的，然而可以通过指示quartz改变这种行为，那属于高级话题）<br /><br /> 2.假如你需要一个java.sql.Connection，用于在execute中完成某些操作，那么你可以把Connection放入Quartz的SchedulerContext中，execute也可以访问，并且Quartz不会持久化SchedulerContext中的任何东西。<br /><br />   scheduler.getContext().put("java.sql.Connection",connection);  <br /><br /> execute中<br />   Connection con = (Connection)jobExecutionContext.getScheduler().getContext().get("java.sql.Connection");
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/158814#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 23 Jan 2008 17:56:14 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/158814</link>
        <guid>http://ordier.javaeye.com/blog/158814</guid>
      </item>
      <item>
        <title>jndi 学习</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/152379" style="color:red;">http://ordier.javaeye.com/blog/152379</a>&nbsp;
          发表时间: 2008年01月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          jndi api java命名/目录服务接口 jdk中自带的3中实现 <br />1. Lightweight Directory Access Protocol (LDAP) <br />2. Common Object Request Broker Architecture (CORBA) Common Object Services (COS) name service <br />3. Java Remote Method Invocation (RMI) Registry <br /><br />和多数java服务一样，SUN对JNDI也只提供接口，使用JNDI只需要用到JNDI接口而不必关心具体实现：<br /><br />private static Object jndiLookup() throws Exception {<br />  InitialContext ctx = new InitialContext();<br />  return ctx.lookup("java:comp/env/systemStartTime");<br />}<br /><br />这样的代码在j2ee环境下能很好的工作，<br />但是如果是客户端程序，或者main函数的方式就会报错：NoInitialContextException<br />这是因为在j2ee环境下 当server启动的时候对jndi的env进行了初始化的配置。<br />其实之所以有NoInitialContextException是因为无法从System.properties中获得必要的JNDI参数，在服务器环境下，服务器启动时就把这些参数放到System.properties中了，于是直接new InitialContext()就搞定了，不要搞env那么麻烦，搞了env你的代码还无法移植，弄不好管理员设置服务器用的不是标准端口还照样抛异常。<br />但是在单机环境下，可没有JNDI服务在运行，那就手动启动一个JNDI服务。我在JDK 5的rt.jar中一共找到了4种SUN自带的JNDI实现：<br /><br />LDAP，CORBA，RMI，DNS。<br /><br />这4种JNDI要正常运行还需要底层的相应服务。一般我们没有LDAP或CORBA服务器，也就无法启动这两种JNDI服务，DNS用于查域名的，以后再研究，唯一可以在main()中启动的就是基于RMI的JNDI服务。<br /><br />现在我们就在main()中启动基于RMI的JNDI服务并且绑一个Date对象到JNDI上：<br /><br />LocateRegistry.createRegistry(1099);<br />System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");<br />System.setProperty(Context.PROVIDER_URL, "rmi://localhost:1099");<br />InitialContext ctx = new InitialContext();<br />class RemoteDate extends Date implements Remote {};<br />ctx.bind("java:comp/env/systemStartTime", new RemoteDate());<br />ctx.close();<br /><br /><br />在RMI中绑JNDI的限制是，绑定的对象必须是Remote类型，所以就自己扩展一个。<br /><br />其实JNDI还有两个Context.SECURITY_PRINCIPAL和Context.SECURITY_CREDENTIAL，如果访问JNDI需要用户名和口令，这两个也要提供，不过一般用不上。
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/152379#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 02 Jan 2008 16:12:41 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/152379</link>
        <guid>http://ordier.javaeye.com/blog/152379</guid>
      </item>
      <item>
        <title>Oracle数据库取消8080端口占用</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/148351" style="color:red;">http://ordier.javaeye.com/blog/148351</a>&nbsp;
          发表时间: 2007年12月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          安装Oracle数据库后，当我们访问8080端口时，会弹出一个XDB窗口，要求输入用户名和密码。这样将和我们本地一些使用该端口的应用冲突，比如tomcat、jboss等，虽然这些端口是可以修改的，但总是不爽oracle一直占用这个端口。以下是我找到的一个方法，我已经试验成功了，如果你想用此法进行修改，请首先备份数据库重要内容，如果操作不慎，难免要重装数据库。 <br />　　Oracle数据库可以使用TCP协议通过8080端口进行连接，所以占用了8080端口。<br />要取消占用，可以打开Oracle安装目录下的database目录内的SPFILE[SID名].ORA文件进行修改。这个文件是Oracle的启动配置文件。<br /><br />　　把其中的*.dispatchers=’(PROTOCOL=TCP) (SERVICE=or9iXDB)’这一行去掉即可。<br /><br />　　然后重启计算机，或者在服务中重启OracleService[SID名]这个服务。重启后可能无法使用Enterprise Manager Console和其他客户端连接，这时请使用Oracle的Configuration and Migration Tools/Net Configuration Assistant工具删除监听器，然后新建一个监听器，重启监听器。<br /><br />　　使用Configuration and Migration Tools/Net Manager工具，将服务命名删除，然后新建一个。<br /><br />　　现在Oracle应该就可以正常使用，8080也不会占用了。<br /><br /><br />原文地址<a href="http://www.nou.com.cn/cms/sjk/6682/page.action" target="_blank">http://www.nou.com.cn/cms/sjk/6682/page.action</a>
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/148351#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 14 Dec 2007 15:00:06 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/148351</link>
        <guid>http://ordier.javaeye.com/blog/148351</guid>
      </item>
      <item>
        <title>rowid 的数据类型</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/147736" style="color:red;">http://ordier.javaeye.com/blog/147736</a>&nbsp;
          发表时间: 2007年12月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          ROWID 数据类型<br /><br />  －－是一行的唯一标识 <br />  －－用于定位行<br /><br />ROWID 的格式<br /><br />   OOOOOO     FFF       BBBBBB    RRR<br />  数据对象号  相对文件号     块号      行号<br /><br />数据对象编号需要32 位，相关文件编号需要10 位，块编号需要22，位行编号需要16 位，加起来总共是80 位或10 个字节<br /><br />数据文件的最大尺寸？<br />32bit---object number--------，每个数据库最多有4G个对象<br />10bit---file number-----，每个数据库最多有1022个文件（2个文件预留）<br />22bit---block number--------，每个文件最多有4M个BLOCK<br />16bit---row number--------，每个BLOCK最多有64K个ROWS<br /><br />ROWID的编码方案和显示<br />ROWID 使用以64 为基数的编码方案来显示，该方案将六个位置用于数据对象编号，三个位置用于相关文件编号，六个位置用于块编号，三个位置用于行编号。<br /><br />以64 为基数的编码方案使用字符A-Z a-z 0-9 + 和/，共64 个字符<br /><br />SQL> select rowid from LUNAR_EMP;<br />ROWID<br />------------------<br />AAAG/LAAGAAAACeAAA<br />SQL><br />AAAG/L 是数据对象编号<br />AAG是相关文件编号<br />AAAACe是块编号<br />AAA 是行编号
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/147736#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 12 Dec 2007 10:47:17 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/147736</link>
        <guid>http://ordier.javaeye.com/blog/147736</guid>
      </item>
      <item>
        <title>向管理要效益－erp的功能设计</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/147478" style="color:red;">http://ordier.javaeye.com/blog/147478</a>&nbsp;
          发表时间: 2007年12月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          企业如何通过ERP的上线来做到精细化的管理，达到向管理要效益，真正提高企业的市场竞争力，这也是企业选择上ERP的初衷<br /><br />1. 客户信用额度控制<br />这是控制财务风险的一个必须的参数，对不同等级的客户有不同的信用额度授权，如果超出该客户的信用额度，可以随时查看该客户信用额度的余额，在新接订单，销售出货和发票开立方面给予提示和控制，对超过信用额度的客户必须重新评估，是否放宽额度还是停止供货，超额度供货而产生的恶意债务甚至会危及企业的生存，这样的例子已经不胜枚举。<br />2. BOM版本控制<br />在制造业企业里面，BOM是最基础的技术资料，它体现了一个产品的结构和组成，它也是运算MRP和MPS的基础，所以，对于如此重要的资料，我们必须保证BOM资料的准确性，由于设计和客户要求等方面的原因，我们会经常对产品BOM做一些变更，产生不同版本的BOM，但是，在同一阶段，有效的BOM版本只能有一个，所以，我们必须严格的控制产品BOM的版本和生效，失效日期，以确定我们引用的BOM是正确的，才能保证后面的MRP和MPS的计算是正确的。<br />3. 料品类型控制<br />我大致看了几家系统，大家都对料品类型做了几个分类，而我个人更倾向于下面的分类：<br />商品：买进卖出，不做其他的加工处理的产品，不少公司的模具就属于此类。其计划属性为采购。<br />制成品：经过原料、半成品等组合而成的最终出货的产品，其计划属性为生产。<br />半成品：经过原料的加工而成，一般做为构成制成品的一部分，也可以单独出货的产品，其计划属性为生产。<br />原料：制成品，半成品的最初组成部分，直接从企业外部购进的产品，其计划属性为采购。<br />物料：低值易耗品，无法在产品BOM确定具体用量的这一类产品，在成本核算是作为制造费用来处理，其计划属性为采购。<br />在制品：正在车间处于加工状态的产品，一般从原料到半成品，成品之间的这种料品状态的属于在制品，由于其在不同的工序之间处于不同的状态，所以，料品编号一般和工序是挂钩的，这也是车间（工序）管理的一个必要条件，有不少系统不具备这一点，所以，在车间管理方面管控的就不严密。<br />4. 未交订单控制<br />在ERP的销售模块，一般的业务人员都会比较关注销售订单的交货情况及未交货情况，所以在这个模块都必须有一支报表来查看销售订单的完成情况，一般是以料号，客户，交货日期，业务员等为查询条件的，我们就可以很明确的查看某一产品，某一客户，某一时间或某一业务员的未交订单状况。如果有预警系统的话，我们可以设定预警的条件，比如说交货期的前2天给予预警，通知业务和仓库人员进行相应的出货准备。<br />5. 出货对帐控制<br />在ERP的销售模块，业务人员和财务人员关心的另一个问题就是出货对帐和回款，现在绝大部分企业与企业之间交易采用的都是月结的这种结算方式，业务人员和仓管人员日常从系统做出货和退货，一般到月底都会进行一次对帐，互相确认对帐金额之后确定应收帐款，所以在销售管理模块一般都会有一支报表来确定某一期间，某一客户的出货金额，退货金额以及应收帐款金额。所以，送货日期区间、客户一般都作为这支报表的查询条件的，来抓取某一时间段、某一客户的交易金额与客户核实，作为财务的最终的应收帐款。<br />6. 销售订单处理跟踪控制<br />在ERP销售模块，业务人员关心的另外一个问题就是已经审核的销售订单是否已经在其他相关部门开始处理了，例如这个销售订单是否已经下达采购计划，是否已经下达生产计划，这也是业务跟单员做业务跟单的必须步骤，所以，一般的业务系统都会要求对已审核的订单是否在系统做相关处理做一个跟踪，是否延迟处理，延迟处理多长时间，系统都会有一个计划跟踪的报表来查看这些未处理订单的情况，并由系统发送预警信息，以便业务跟单人员和相关计划人员更好的处理相关订单的。<br />7. 销售订单交期模拟预测分析<br />在ERP销售模块，业务人员还会遇到一种情况就是客户在下单之前会向业务跟单人员询问：如果我跟你下某一数量的某种产品，你回复我一下大概的交货期，客户会根据你回复的交期来确定是否下订单给你的企业，这个时候，系统必须具有模拟生产的预测分析的功能，当你输入一定数量的某个产品时，系统根据你的产品BOM，产品工艺路线，单件加工时间，每天生产量，各车间产能，已经分配产能等信息来预测你的订单的大致交货期，给客户一个比较准确的回复。这对企业接单还是有一定作用的。<br />8. 销售业绩分析<br />在ERP销售模块，公司高层一般在年中或者年末的时候都会要求业务部门或者财务部门对销售的业绩提供一个分析，分析的主要分类一是以客户销售金额为指标的，做一个销售排行榜，将客户做一个分类，如重点客户，一般客户等来不同的对待；二是以产品销售金额为指标，对所有产品的销售做一个排行榜，便于找出那些产品是畅销产品，是客户喜爱的产品，对销售的预测和安排生产都有一个参考的作用。这是决策分析的一张报表。<br />9. 采购未交订单控制<br />在ERP的采购模块，采购人员都会关注采购订单的交货情况及未交货情况，所以在采购管理这个模块都必须有一支报表来查看采购订单的完成情况，一般是以料号，供应商，交货日期，采购员等为查询条件的，我们就可以很明确的查看某一材料，某一供应商，某一时间或某一采购员的未交订单状况。采购人员必须进行物料的跟催，以便更好的为生产服务，如果有预警系统的话，我们可以设定预警的条件，比如说交货期的前2天给予预警，通知采购人员和仓库人员进行相应的收货准备。<br />10. 采购对帐控制<br />在ERP的采购模块，采购人员和财务人员关心的另一个问题就是采购对帐和付款，现在绝大部分企业与企业之间交易采用的都是月结的这种结算方式，采购人员和仓管人员日常从系统做采购入库和退货，一般到月底都会进行一次对帐，互相确认对帐金额之后确定应付帐款，所以在采购管理模块一般都会有一支报表来确定某一期间，某一供应商的采购入库金额，退货金额以及应付帐款金额。所以，入库日期区间、供应商一般都作为这支报表的查询条件的，来抓取某一时间段、某一供应商的交易金额与供应商核实，作为财务的最终的应付帐款。<br />11. 采购排行分析<br />在ERP采购模块，公司高层一般在年中或者年末的时候都会要求采购部门或者财务部门对采购的汇总提供一个分析，分析的主要分类一是以采购供应商金额为指标的，做一个供应商排行榜，将供应商做一个分类，如合作伙伴，一般供应商等来不同的对待；二是以材料采购金额为指标，对所有材料的采购做一个排行榜，便于找出那些材料是采购的重点，可以根据采购数量要求供应商做一些价格的优惠等，也可以要求仓库人员对重点材料做重点管控。这是决策分析的又一张报表。<br />12. 库存查询及跟踪<br />在ERP的库存模块，最常用的功能是产品库存量查询功能了，查看某一产品存放在某一仓库某一区域的库存量为多少，或者某一批号库存量为多少，这个很容易实现。但是，如果想对这一产品库存量的来源做一个跟踪很多系统就无法办到了，要了解是由哪些单据生成了当前的库存量，可以对产品来源做一个回溯，也符合ISO的追溯原则的。并且这些仓库库存数量和会计记帐数量是否一致？不一致的话，你的成本核算起来肯定是错误的，这个对财务检查成本核算差异非常的有用处，也是ERP系统集成功能的一个体现。<br />13. 库存呆料分析<br />在ERP库存管理方面，很多物料会由于保存时间和保存环境的变化，其产品特性就有可能发生变化，物料的价值就会降低，甚至会完全报废，这样就会对公司的流动资产造成大量的浪费，并且带来管理成本的增加，所以，作为仓库的物料管理人员必须提供相关物料的呆料分析报表，如：物料的仓库保存期限范围，数量，金额等信息，给相关人员一个提供一个物料使用和安排生产的一个优先参考的依据，尽量避免物料的浪费，降低公司运营成本，真正增加企业效益和竞争力。尤其对于预测生产的企业非常有决策作用。<br />14. 库存盘点分析<br />在ERP的库存管理模块，一般的制造业的工厂，在月末或者一定时间都会做一次工厂库存盘点，盘查仓库库存数量和仓库帐面数量是否一致；在理论上，仓库实物数量应该与仓库帐面数量一致，但是由于管理不严格（如：实物已入库、仓库帐面未入库；实物已发出、仓库帐面未出库；偷盗，丢失等）原因，一般情况下，库存实物数量与仓库帐面数量都会有差异，仓库人员必须在一定时间以后，对库存的实物做一个盘点。盘点的作用有三：1.确定真实的物料库存数量，为生产提供真实的物料信息；2.对盘点差异做出分析，查出管理上的漏洞，追究相关人员的责任过失，并加强管理；3.对盘点差异的物料金额，财务要做制造费用或者管理费用来处理，作为期末生产成本的分摊。所以，对于库存管理的一个重点就是库存盘点作业，公司必须高度重视起来，因为物料成本在制造业的企业中占有很大的比重。<br />15. 库存进销存月报表<br />在ERP的库存管理模块，财务人员一般在月底都要求仓管人员提供一份库存的进销存的月报表，因为对于一般的中小型的制造业来说，一般不具备拥有IE（工业工程）部门，所以对标准工时，实际工时的测量一般都无法做到，那么对于成本核算来说，就无法精确进行制造费用，人工工资的分摊，成本核算只能简单的核算到材料的成本而已。所以财务人员就需要仓库人员提供一份各种物料的进销存月报表，把材料的平均单价计算出来，把实际材料耗用计算出来，那么月末的材料成本就计算出来了，再加上制造费用，人工工资，委外工缴费，那么该月的总生产成本就基本计算出来了。所以，对中小型的制造业来说，必须有这样一支报表来提供给财务人员做成本核算之用。<br />16. MRP的计算过程<br />在ERP的计划管理模块，企业PMC部门的相关计划人员就会做出相关的物料需求计划（MRP）和主生产计划（MPS），我先大致先描述一下MRP的运算过程，ERP系统材料需求计划就是通过BOM的低阶码展开来运算，在运算MRP之前先了解以下术语：低阶码，独立需求，相关需求；总需求量（销售订单，销售预测），库存量，安全库存量，暂收量，在途量（计划在途，采购在途，制造在途），已分配量，被替代量，替代比率，替代优先级，计划库存，净需求量等基本概念，其计算公式：<br />净需求量=总需求量-库存量+安全库存量-暂收量-在途量+已分配量-被替代量<br />这是ERP系统的物料需求计划的计算过程，如果希望运算得出准确的结果，必须保证中间过程的数据准确性，这就是为什么很多公司无法真正跑顺畅MRP的计算的。<br />17. MPS运算过程<br />在ERP的计划模块，企业的PMC部门会做出相关的物料需求计划（MRP）和主生产计划（MPS），上一段已经讲了物料需求计划（MRP），这次描述一下MPS的运算过程，现在的ERP基本采用的都是无限产能的排程法，通过提前期（采购提前期，生产提前期）+参与MRP运算的休息日倒推出计划下达（生产计划，采购计划）日期，这只是一个粗能力需求计划；但是对于企业来说，产能基本是固定的（机器，人员都是固定的），我们还必须考虑我们的产能能否满足系统的计划排程，所以，我们必须确定每个车间的每天总有效工时，每件产品的每道工序的单件加工时间，前置时间等，系统计算出已经安排生产的工单的总计划耗用工时，和每天总有效工时进行对比，从而确定产能是否超短耗，ERP系统最好能随时查看是哪些计划工单占用了这些工时，只有如此，才能对超耗的工单进行排程调整，从而使我们的排程是可行的，这就是细能力计划。<br />18. 生产计划排程跟踪表<br />在ERP制造模块，我们已经做了有效的细生产能力排程，至于计划排程的达成情况，我们必须有报表可供查询，查询我们每天每个加工中心安排生产计划多少，实际达成多少，累计达成多少，当天差异多少，累计差异多少，作为PMC人员和车间管理人员可以随时查看当天或者一个阶段的计划达成情况的，可以随时了解生产状况的，对于差异的情况随时查找原因，采取一些调整方法，以使生产计划能够准时达成，这样才不会造成随意加班和生产混乱的情况出现。<br />19. 工单用料分析表<br />在ERP的制造模块，我们在材料的使用之前必须在系统做套料分析，计算每张工单的应发料数（排产数量*BOM的标准用量），同时对于已经生产和已经完工的工单，必须有报表来查询该工单的应发数量，实发数量，实际耗用量，超领料量，不良报废量，盘点差异量，在制量等相关信息，分析我们的材料使用是否符合我们的计划标准，如果不符合，找出问题的差异所在，进行分析和改进，同时进行材料的使用调整，使生产能有计划的合理进行。在生产计划排程跟踪表我们反映的是生产计划的达成情况，而工单用量分析表则反映的是材料计划的达成情况。<br /><br /><br />原创文章链接：<br /><a href="http://www.itpub.net/viewthread.php?tid=643285&extra=&page=1" target="_blank">http://www.itpub.net/viewthread.php?tid=643285&extra=&page=1</a>
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/147478#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 11 Dec 2007 10:07:52 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/147478</link>
        <guid>http://ordier.javaeye.com/blog/147478</guid>
      </item>
      <item>
        <title>oracle数据库性能总结</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/147287" style="color:red;">http://ordier.javaeye.com/blog/147287</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Oracle性能优化<br />一、SGA<br /><br />1.	Shared pool的优化应该放在优先考虑，因为一个cache miss在shared pool中发生比在data buffer中发生导致的成本更高，由于dictionary数据一般比library cache中的数据在内存中保存的时间长，所以关键是library cache的优化。<br />    Gets：（parse）在namespace中查找对象的次数；<br />    Pins：（execution）在namespace中读取或执行对象的次数；<br />    Reloads：(reparse)在执行阶段library cache misses的次数，导致sql需要重新解析。 <br />    1） 检查v$librarycache中sql area的gethitratio是否超过90％，如果未超过90％，应该检查应用代码，提高应用代码的效率。<br />    Select gethitratio from v$librarycache where namespace=’sql area’;<br />    2) v$librarycache中reloads/pins的比率应该小于1％，如果大于1％，应该增加参数shared_pool_size的值。<br />    Select sum(pins) “executions”,sum(reloads) “cache misses”,sum(reloads)/sum(pins) from v$librarycache;<br />    reloads/pins>1%有两种可能，一种是library cache空间不足，一种是sql中引用的对象不合法。<br />    3）shared pool reserved size一般是shared pool size的10％，不能超过50％。V$shared_pool_reserved中的request misses＝0或没有持续增长，或者free_memory大于shared pool reserved size的50%，表明shared pool reserved size过大，可以压缩。<br />    4）将大的匿名pl/sql代码块转换成小的匿名pl/sql代码块调用存储过程。<br />    5）从9i开始，可以将execution plan与sql语句一起保存在library cache中，方便进行性能诊断。从v$sql_plan中可以看到execution plans。<br />    6）保留大的对象在shared pool中。大的对象是造成内存碎片的主要原因，为了腾出空间许多小对象需要移出内存，从而影响了用户的性能。因此需要将一些常用的大的对象保留在shared pool中，下列对象需要保留在shared pool中：<br />    a. 经常使用的存储过程；<br />    b. 经常操作的表上的已编译的触发器<br />    c. Sequence，因为Sequence移出shared pool后可能产生号码丢失。<br />    查找没有保存在library cache中的大对象：<br />    Select * from v$db_object_cache where sharable_mem>10000 and type in ('PACKAGE','PROCEDURE','FUNCTION','PACKAGE BODY') and kept='NO';<br />    将这些对象保存在library cache中：<br />    Execute dbms_shared_pool.keep(‘package_name’);<br />    对应脚本：dbmspool.sql<br />    7)查找是否存在过大的匿名pl/sql代码块。两种解决方案：<br />    A．转换成小的匿名块调用存储过程<br />    B．将其保留在shared pool中<br />    查找是否存在过大的匿名pl/sql块：<br />    Select sql_text from v$sqlarea where command_type=47 and length(sql_text)>500;<br />    8）Dictionary cache的 优化 <br />    避免出现Dictionary cache的misses，或者misses的数量保持稳定,只能通过调整shared_pool_size来间接调整dictionary cache的大小。<br />    Percent misses应该很低：大部分应该低于2％，合计应该低于15％<br />    Select sum(getmisses)/sum(gets) from v$rowcache;<br />    若超过15％，增加shared_pool_size的值。<br />    2、Buffer Cache<br />    1）granule大小的设置，db_cache_size以字节为单位定义了default buffer pool的大小。<br />    如果SGA&lt;128M，granule=4M,否则granule＝16M，即需要调整sga的时候以granule为单位增加大小，并且sga的大小应该是granule的整数倍。<br />    2) 根据v$db_cache_advice调整buffer cache的大小<br />    SELECT size_for_estimate,buffers_for_estimate,estd_physical_read_factor,estd_physical_reads FROM v$db_cache_advice WHERE NAME='DEFAULT' AND advice_status='ON' AND block_size=(SELECT Value FROM v$parameter WHERE NAME='db_block_size');<br />    estd_physical_read_factor&lt;=1<br />    3) 统计buffer cache的cache hit ratio>90%，如果低于90％，可以用下列方案解决：<br />    增加buffer cache的值；<br />    使用多个buffer pool；<br />    Cache table；<br />    为 sorting and parallel reads 建独立的buffer cache；<br />    SELECT NAME,value FROM v$sysstat WHERE NAME IN ('session logical reads','physical reads','physical reads direct','physical reads direct(lob)');<br />    Cache hit ratio=1-(physical reads-physical reads direct-physical reads direct (lob))/session logical reads;<br />    Select 1-(phy.value-dir.value-lob.value)/log.value from v$sysstat log, v$sysstat phy, v$sysstat dir, v$sysstat LOB where log.name='session logical reads' and phy.name='physical reads' and dir.name='physical reads direct' and lob.name='physical reads direct (lob)';<br />    影响cache hit ratio的因素：<br />    全表扫描；应用设计；大表的随机访问；cache hits的不均衡分布<br />    4）表空间使用自动空间管理，消除了自由空间列表的需求，可以减少数据库的竞争<br />    3、其他SGA对象<br />    1）redo log buffer<br />    对应的参数是log_buffer，缺省值与 OS相关，一般是500K。检查v$session_wait中是否存在log buffer wait,v$sysstat中是否存在redo buffer allocation retries<br />    A、检查是否存在log buffer wait：<br />    Select * from v$session_wait where event=’log buffer wait’ ;<br />    如果出现等待，一是可以增加log buffer的大小，也可以通过将log 文件移到访问速度更快的磁盘来解决。<br />    B、Select name,value from v$sysstat where name in (‘redo buffer allocation retries’,’redo entries’)<br />    Redo buffer allocation retries接近0，小于redo entries 的1％，如果一直在增长，表明进程已经不得不等待redo buffer的空间。如果Redo buffer allocation retries过大，增加log_buffer的值。<br />    C、检查日志文件上是否存在磁盘IO竞争现象<br />    Select event,total_waits,time_waited,average_wait from v$system_event where event like ‘log file switch completion%’;<br />    如果存在竞争，可以考虑将log文件转移到独立的、更快的存储设备上或增大log文件。<br />    D、检查点的设置是否合理<br />    检查alert.log文件中，是否存在‘checkpoint not complete’；<br />    Select event,total_waits,time_waited,average_wait from v$system_event where event like ‘log file switch (check%’;<br />    如果存在等待，调整log_checkpoint_interval、log_checkpoint_timeout的设置。<br />    E、检查log archiver的工作<br />    Select event,total_waits,time_waited,average_wait from v$system_event where event like ‘log file switch (arch%’;<br />    如果存在等待，检查保存归档日志的存储设备是否已满，增加日志文件组，调整log_archiver_max_processes。<br />    F、DB_block_checksum=true，因此增加了性能负担。（为了保证数据的一致性，oracle的写数据的时候加一个checksum在block上，在读数据的时候对checksum进行验证）<br />2）java pool<br />    对于大的应用，java_pool_size应>=50M，对于一般的java存储过程，缺省的20M已经够用了。<br />    3）检查是否需要调整DBWn<br />    Select total_waits from v$system_event where event=’free buffer waits’;<br /><br />二、数据库配置和IO问题<br />    降低磁盘的IO<br />    分散磁盘的IO<br />    表空间使用本地管理<br />    1、将文件分散到不同的设备上<br />    1）将数据文件与日志文件分开<br />    2）减少与服务器无关的磁盘IO<br />    3）评估裸设备的使用<br />    4）分割表数据<br />    2、表空间的使用<br />    系统表空间保留给数据字典对象<br />    创建本地管理表空间以避免空间管理问题<br />    将表和索引分散到独立的表空间中<br />    使用独立的回滚表空间<br />    将大的数据库对象保存在各自独立的表空间中<br />    创建一个或多个独立的临时表空间<br />    下列数据库对象应该有单独的表空间：<br />    数据字典、回滚段、索引、临时段、表、大对象<br />    3、检查IO统计数据<br />    Select phyrds,phywrts,d.name from v$datafile d,v$filestat f where f.file#=d.file# order by d.name;<br />    检查最有可能引起磁盘IO瓶颈的文件。<br />    4、分割文件<br />    可以通过RAID和手工进行<br />    Alter table table_name allocate extent (datafile ‘fiile_name’ size 10M);<br />    但手工操作工作量很大。<br />    5、优化全表扫描操作<br />    1）检查有多少全表发生：<br />    Select name,value from v$sysstat where name like ‘%table scan%’;<br />    table scans (short tables)/ table scans (long tables)与全表扫描相关，如果table scans (long tables)的值很高，说明大部分的table access 没有经过索引查找，应该检查应用或建立索引，要确保有效的索引在正确的位置上。<br />    合理的DB_FILE_MULTIBLOCK_READ_COUNT能减少table scan需要调用的IO次数，提高性能（与OS相关）。<br />    2）查看full table scan操作：<br />    Select sid,serial#,opname,target，to_char(start_time,’HH24:MI:SS’) “start”,(sofar/totalwork)*100 “percent_complete” from v$session_longops;<br />    通过v$session_longops里的sql_hash_value与v$sqltext关联，可以查询导致full table scan的sql。<br />    6、Checkpoint<br />    Checkpoint进行的操作：DBWn进行IO操作；CKPT更新数据文件头和控制文件。<br />    经常进行Checkpoint的结果：减少恢复所需的时间；降低了系统运行时的性能。<br />    LGWR以循环的方式将日志写到各个日志组，当一个日志组满时，oracle server必须进行一个Checkpoint，这意味着：DBWn将对应log覆盖的所有或部分脏数据块写进数据文件；CKPT更新数据文件头和控制文件。如果DBWn没有完成操作而LGWR需要同一个文件，LGWR只能等待。<br />    在OLTP环境下，如果SGA很大并且checkpoint的次数不多，在Checkpoint的过程中容易出现磁盘竞争的状况，在这种情况下，经常进行Checkpoint可以减少每次Checkpoint涉及到的脏数据块的数目。<br />    调节Checkpoint次数的办法：<br />    增大日志文件；增加日志组以增加覆盖的时间间隔。<br />    7、日志文件<br />    建立大小合适的日志文件以最小化竞争；<br />    提供足够的日志文件组以消除等待现象；<br />    将日志文件存放在独立的、能快速访问的存储设备上（日志文件可以创建在裸设备上）。日志文件以组的方式组织管理，每个组里的日志文件的内容完全相同。<br />    8、归档日志文件<br />    如果选择归档模式，必须要有两个或两个以后的日志组，当从一个组切换到另一个组时，会引起两种操作：DBWn进行Checkpoint；一个日志文件进行归档。<br />    归档有时候会报错：<br />    ARC0：Beginning to archive log# 4 seq# 2772<br />    Current log# 3 seq# 2773……<br />    ARC0: Failed to archive log# 4 seq# 2772<br />    ARCH: Completed to archiving log#4 seq# 2772<br />    建议init参数修改如下：<br />    log_archive_max_processes=2<br />    #log_archive_dest = ‘/u05/prodarch’<br />    log_archive_dest_1 = "location=/u05/prodarch MANDATORY’<br />    log_archive_dest_state_1 = enable <br />    log_archive_dest_2 = "location=/u05/prodarch2 OPTIONAL reopen=10" （或其它目录）<br />    log_archive_dest_state_2 = enable <br />    log_archive_min_succeed_dest=1<br />    log_archive_dest_state_3 = DEFER<br />    log_archive_dest_state_4 = DEFER<br />    log_archive_dest_state_5 = DEFER<br />三、优化排序操作<br />    1、概念<br />    服务器首先在sort_area_size指定大小的内存区域里排序，如果所需的空间超过sort_area_size，排序会在临时表空间里进行。在专用服务器模式下，排序空间在PGA中，在共享服务器模式下，排序空间在UGA中。如果没有建立large pool，UGA处于shared pool中，如果建立了large pool，UGA就处于large pool中，而PGA不在sga中，它是与每个进程对应单独存在的。<br />     PGA：program global area,为单个进程（服务器进程或后台进程）保存数据和控制信息的内存区域。PGA与进程一一对应，且只能被起对应的进程读写，PGA在用户登录数据库创建会话的时候建立。<br />    有关排序空间自动管理的两个参数：<br />    Pga_aggregate_target: 10M-4000G，等于分配给oracle instance的所有内存减去SGA后的大小。 <br />    Workarea_size_policy: auto/manual，只有Pga_aggregate_target已定义时才能设置为auto。<br />    这两个参数会取代所有的*_area_size参数。<br />    措施：<br />    尽可能避免排序；尽可能在内存中排序；分配合适的临时空间以减少空间分配调用。<br />    2、需要进行排序的操作：<br />    A、创建索引；<br />    B、涉及到索引维护的并行插入<br />    C、order by或者group by（尽可能对索引字段排序）<br />    D、Distinct<br />    E、union/intersect/minus<br />    F、sort-merge join<br />    G、analyze命令（仅可能使用estamate而不是compute）<br />    3、诊断和措施<br />    Select * from v$sysstat where name like ‘%sort%’;<br />    Sort(disk):要求Io去临时表空间的排序数目<br />    Sort(memory)：完全在memory中完成的排序数目<br />    Sort(rows)：被排序的行数合计<br />    Sort（disk）/ Sort（memory）&lt;5%,如果超过5％，增加sort_area_size的值。<br />    SELECT disk.Value disk,mem.Value mem,(disk.Value/mem.Value)*100 ratio FROM v$sysstat disk,v$sysstat mem WHERE mem.NAME='sorts (memory)' AND disk.NAME='sorts (disk)';<br />    4、监控临时表空间的使用情况及其配置<br />    Select tablespace_name,current_users,total_extents,used_extents,extent_hits,max_used_blocks,max_sort_blocks FROM v$sort_segment ;<br />    Column Description <br />    CURRENT_USERS Number of active users <br />    TOTAL_EXTENTS Total number of extents <br />    USED_EXTENTS Extents currently allocated to sorts <br />    EXTENT_HITS Number of times an unused extent was found in the pool <br />    MAX_USED_BLOCKS Maximum number of used blocks <br />    MAX_SORT_BLOCKS Maximum number of blocks used by an individual sort <br />    临时表空间的配置：<br />    A、initial/next设置为sort_area_size的整数倍，允许额外的一个block作为segment的header<br />    B、pctincrease=0<br />    C、基于不同的排序需要建立多个临时表空间<br />    D、将临时表空间文件分散到多个磁盘上<br />四、诊断latch竞争<br />    1、概念<br />    Latch是简单的、低层次的序列化技术，用以保护SGA中的共享数据结构，比如并发用户列表和buffer cache里的blocks信息。一个服务器进程或后台进程在开始操作或寻找一个共享数据结构之前必须获得对应的latch，在完成以后释放latch。不必对latch本身进行优化，如果latch存在竞争，表明SGA的一部分正在经历不正常的资源使用。<br />    1）Latch的作用：<br />    A、序列化访问：保护SGA中的共享数据结构；保护共享内存的分配。<br />    B、序列化执行：避免同时执行某些关键代码；避免互相干扰。<br />    2）Latch请求的两种类型：<br />    A、willing-to-wait：请求的进程经过短时间的等待后再次发出请求，直到获得latch<br />    B、immediate：如果没有获得latch，请求的进程不等待，而是继续处理其他指令。<br />    2、检查Latch竞争<br />    检查latch free是不是主要的wait event：<br />    Select * from v$system_event order by time_waited;<br />    检查latch的使用情况：<br />    Select * from v$latch:<br />    与willing-to-wait请求有关的列：gets、misses、sleeps、wait_time、cwait_time、spin_gets<br />    与immediate请求有关的列：immediate_gets、immediate_misses<br />    Gets: number of successful willing-to-wait requests for a latch;<br />    Misses: number of times an initial wiling-to-wait request was unsuccessful;<br />    Sleeps: number of times a process waited after an initial willing-to-wait request;<br />    Wait_time: number of milliseconds waited after willing-to-wait request;<br />    Cwait_time: a measure of the cumulative wait time including the time spent spinning and sleeping,the overhead of context switches due to OS time slicing and page faults and interrupts;<br />    Spin_gets: gets that misses first try but succeed after spinning.<br />    Immediate_gets: number of successful immediate requests for each latch;<br />    Immediate_misss: number of unsuccessful immediate requests for each latch;<br />    一般无需调整latch，但是下列的措施是有用的：<br />    A、对处于竞争中的latch做进一步的调查<br />    B、如果竞争主要存在于shared pool和library cache中，可以考虑调整应用<br />    C、如果进一步的调查显示需要调整shared pool和buffer cache，就进行调整<br />    Select * from v$latch where name like ‘%shared pool%’ or name like ‘%library cache%’；<br />    如果竞争是在shared pool或library cache上，表示下列集中情况：<br />    A、不能共享的sql,应检查他们是否相似，考虑以变量代替sql中的常量：<br />    Select sql_text from v$sqlarea where executions=1 order by upper(sql_text);<br />    B、共享sql被重新编译，考虑library cache的大小是否需要调整：<br />    SELECT sql_text,parse_calls,executions FROM v$sqlarea where parse_calls>5;<br />    C、library cache不够大。<br />五、Rollback(undo) Segment 优化<br />    1、概念<br />    Transaction以轮循的方式使用rollback segment里的extent，当前所在的extent满时就移动到下一个extent。可能有多个transaction同时向同一个extent写数据，但一个rollback segment block中只能保存一个transaction的数据。<br />    Oracle 在每个Rollback segment header中保存了一个transaction table，包括了每个rollback segment中包含的事务信息，rollback segment header的活动控制了向rollbak segment写入被修改的数据。rollback segment header是经常被修改的数据库块，因此它应该被长时间留在buffer cache中，为了避免在transaction table产生竞争导致性能下降，应有多个rollback segment或应尽量使用oracle server 自动管理的rollback segment。<br />    2、诊断rollback segment header的竞争<br />    如果rollback segment 由手工管理，下列措施诊断rollback segment header的竞争<br />    SELECT class,count FROM v$waitstat WHERE class LIKE '%undo%' ;<br />    SELECT Sum(Value) sum FROM v$sysstat WHERE NAME IN ('db block gets','consistent gets');<br />    任何类型的等待次数（count）与总请求数(sum)的比率，不能超过1％。<br />    或<br />    select sum(waits)*100/sum(gets) "Ratio", sum(waits) "Waits", sum(gets) "Gets" from v$rollstat;<br />    waits的汇总数与gets的汇总数的比率应低于1％，如果超过1％，应创建更多的rollback segment。<br />    下列字段数值如果大于0，则表明在rollback segment header上存在竞争：<br />    A、v$rollstat 中的waits<br />    B、v$waitstat中的undo header行<br />    C、v$system_event中的undo segment tx slot事件<br />    3、消耗更少的rollback segment<br />    1）如果是删除表里所有的数据，尽可能使用trauncate而不是delete。<br />    2）在应用中允许用户有规律的提交，尽可能不用长事务。<br />    3）? Import<br />    – Set COMMIT = Y<br />    – Size the set of rows with BUFFER<br />    ? Export: Set CONSISTENT=N<br />    ? SQL*Loader: Set the COMMIT intervals with ROWS<br />    4、小回滚段可能出现的问题<br />    A、事务由于缺少回滚空间失败<br />    B、由于下列原因导致的“Snapshot too old”问题：<br />    Block里的事务列表被刷新，block里的SCN比列表Interested Transaction List（ITL）里起始事务的SCN更新；<br />    Rollback segment header里的Transaction slot被重用；<br />    回滚数据已经被重写；<br />    5、9i的自动回滚管理<br />    Undo_managment指定了回滚空间的管理方式：Auto：自动管理；Manual：手工管理回滚段。<br />    Undo_retention指定了回滚数据的保留期限；<br />    Undo_tablespace指定了被使用的回滚表空间；<br />    Oracle自动管理的表空间可以在常见数据库的时候创建，也可以单独建立。回滚表空间可以相互转换（switch），但在某一时刻只能有一个回滚表空间处于活动状态。回滚表空间处于非活动状态时可以删除，如果有对处于被删除回滚表空间里的已提交事务的查询时，oracle会返回一个错误。<br />    估计undo tablespace大小的公式：<br />    Undo space = (undo_retention * (undo blocks per second * db_block_size)) + db_block_size;<br />    可以使用下列的sql设定undo_retention和undo tablespace：<br />    select (rd*(ups*overhead)+overhead) "bytes" from (select value rd from v$parameter where name ='undo_retention'),(select (sum(undoblks)/sum(((end_time-begin_time)*10800))) ups from v$undostat),(select value overhead from v$parameter where name='db_block_size');<br />    其中：<br />    Rd：undo_retention设置的时间；<br />    Ups：undo blocks per second；<br />    Overhead：rollback segment header；<br />六、Lock Contention<br />    1、概念<br />    DML事务使用row-level locks,查询不会锁定数据。锁有两种模式：exlusive、share。<br />    锁的类型：<br />    ? DML or data locks:<br />    – Table-level locks（TM）<br />    – Row-level locks（TX）<br />    ? DDL or dictionary locks<br />    一个transaction至少获得两个锁：一个共享的表锁，一个专有的行锁。Oracle server将所有的锁维护在一个队列里，队列跟踪了等待锁的用户、申请锁的类型以及用户的顺序信息。<br />    Lock在下列情况会释放：commit；rollback；terminated（此时由pmon清理locks）。Quiesced database：一个数据库如果除了sys和system之外没有其他活动session，这个数据库即处于quiesced状态。活动session是指这个session当前处于一个transaction中，或一个查询中，一个fetch中，或正占有某种共享资源。<br />    2、可能引起lock contention的原因<br />    不必要的高层次的锁；<br />    长时间运行的transaction；<br />    未提交的修改；<br />    其他产品施加的高层次的锁。<br />    解决lock contention的方法：锁的拥有者提交或回滚事务；杀死用户会话。<br />    3、死锁<br />    Oracle自动检测和解决死锁，方法是通过回滚引起死锁的语句（statement），但是这条语句对应的transaction并没有回滚，因此当收到死锁的错误信息后，应该去回滚改transaction的剩余部分。<br />七、应用优化<br />    1、概念<br />    为了提高性能，可以使用下列数据访问方法：<br />    A、Clusters<br />    B、Indexes<br />    -B-tree（normal or reverse key）<br />    -bitmap<br />    -function-based<br />    C、Index-organized tables<br />    D、Materialized views<br />    索引的层次越多，效率越低，如果索引中含有许多已删除的行，这个索引也会变得低效，如果索引数据的15％已经被删除，应该考虑重建索引。<br />    2、应用问题<br />    A、使用可声明的约束而不是通过代码限制<br />    B、代码共享<br />    C、使用绑定变量而不是文字来优化共享sql<br />    D、调整cursor_sharing的值（EXACT/SIMILAR/FORCE）<br />八、提升block的效率<br />    1、避免动态分配的缺陷<br />    创建本地管理的表空间；<br />    合理设置segment的大小；<br />    监控将要扩展的segment：<br />    SELECT owner, table_name, blocks, empty_blocks FROM dba_tables WHERE empty_blocks / (blocks+empty_blocks) &lt; .1;<br />    2、high water mark<br />    记录在segment header block中，在segment创建的时候设定在segment的起始位置，当记录被插入的时候以5个block的增量增加，truncate可以重设high water mark的位置，但delete不能。<br />    在full table scan中，oracle会读取high water mark以下的所有的数据块，所以high water mark以上的块也许会浪费存储空间，但不会降低性能。<br />    可以通过下列方法收回表中high water mark以上的块：<br />    Alter table_name deallocate unused；<br />    对于high water mark以下的块：<br />    使用import/export工具：export数据；drop或truncate表；import数据。或者利用alter table tanle_name move命令去移动表的存储位置（此时需要重建索引）。<br />    3、表统计<br />    用analyize命令生成表统计，然后到dba_table查询相关信息。<br />    ANALYZE TABLE ndls.t_wh_shipping_bill COMPUTE STATISTICS;<br />    SELECT num_rows, blocks, empty_blocks as empty,avg_space, chain_cnt, avg_row_len FROM dba_tables WHERE owner ='NDLS' AND table_name='T_WH_SHIPPING_BILL';<br />    Columns Description <br />    NUM_ROWS Number of rows in the table <br />    BLOCKS Number of blocks below the table high-water mark <br />    EMPTY_BLOCKS Number of blocks above the table high-water mark <br />    AVG_SPACE Average free space in bytes in the blocks below high-water mark<br />    AVG_ROW_LEN Average row length, including row overhead <br />    CHAIN_CNT Number of chained or migrated rows in the table <br />    4、block size<br />    通过下列方法可以最小化block的访问次数：<br />    使用更大的block size；紧密压缩行；阻止行镜像。后两者存在冲突，越多的行被压缩在一个block里，越容易产生镜像。Block size 在数据库创建的时候设定，不能被轻易改变，是读取数据文件时最小的IO单元，大小范围是2K－64K，应该设置成OS块的整数倍，小于或等于OS IO时能读取的存储区域。<br />    较小的block size的优点：极少block竞争；有利于较小的行和随机访问。缺点是存在相当高的成本，每个block的行数更少，可能需要读取更多的index块。Block size的选择影响系统的性能，在一个OLTP环境中，较小的block size更合适，而在DSS环境中，适宜选择较大的block size。<br />5、PCTFREE、PCTUSED<br />    1）PCTFREE、PCTUSED使你能控制一个segment里所有数据块里free space的使用。<br />    PCTFREE：一个数据块保留的用于块里已有记录的可能更新的自由空间占block size的最小比例。<br />    PCTUSED：在新记录被插入block里之前这个block可以用于存储行数据和其他信息的空间所占的最小比率。<br />    2）这两个参数的使用<br />    如果创建表的时候指定pctfree＝20％，oracle会在这个表的data segment的每个block都保留20％的空间用于已有记录的更新。Block的已使用空间上升到整个block size的80％时，这个block将移出free list；在提交了delete、update之后，oracle server处理这条语句并检查对应block的已使用空间是否低于PCTUSED，如果是，则这个block放进free list。<br />    3）PCTFREE、PCTUSED的设定<br />    ? PCTFREE<br />    – Default 10<br />    – Zero if no UPDATE activity<br />    – PCTFREE = 100 × upd / (average row length)<br />    ? PCTUSED<br />    – Default 40<br />    – Set if rows deleted<br />    – PCTUSED = 100 – PCTFREE – 100 × rows × (average row length) / blocksize<br />    其中，upd ： the average amount added by updates, in bytes。This is determined by subtracting the average row length of intercurrent average row length;<br />    average row length：在运行了analyize命令之后，这个值可以从dba_tables中的avg_row_len列中获得。<br />    rows ： the number of rows to be deleted before free list maintenance occurs。<br />    4）Delete、update可以增加block的自由空间，但是释放出来的空间有可能是不连续的，oracle在下列情况下会对碎片进行整理：一个block有足够的自由空间容纳row piece，但是由于每个碎片都较小以至这个row piece不能存放在一个连续的section中。<br />    6、Migration和Chaining<br />    1）如果一行的数据太大以至一个单独的block容纳不下，会产生两种现象：<br />    A、Chaining：行数据太大以至一个空block容纳不下，oracle会将这一行的数据存放在一个或多个block 组成的block chain中，insert、update都可能导致这个问题，在某些情况下row chaining是不能避免的。<br />    B、Migration：一次update操作可能导致行数据增大，以至它所在的block容纳不下，oracle server会去寻找一个有足够自由空间容纳整行数据的block，如果这样的block存在，oracle server把整行移到新的block，在原位置保存一个指向新存放位置的镜像行，镜像行的rowid和原来的rowid一致。<br />    Chaining、Migration的弊端：insert、update的性能降低，索引查询增加了IO次数。<br />    2）检测migration和chaining：<br />    Analyize table table_name compute statistics；<br />    Select num_rows,chain_cnt from dba_tables where table_name=’...’;<br />    查询镜像行：<br />    Analyize table table_name list chained rows；<br />    Select owner_name,table_name,head_rowid from chained_rows where table_name=’...’;<br />    产生Migration的原因可能是由于PCTFREE设置的太低以至没有保留足够的空间用于更新。<br />    可以通过增加PCTFREE的值避免行镜像产生。<br />    3）消除镜像行的步骤：<br />    运行analyize table ... list chained rows;<br />    复制镜像行到另一个表tmp；<br />    从源表中删除这些行；<br />    从tmp中将这些行插回到源表中。<br />    脚本：<br />    /* Get the name of the table with migrated rows */<br />    accept table_name prompt ’Enter the name of the table with migrated rows: ’<br />    /* Clean up from last execution */<br />    set echo off<br />    drop table migrated_rows;<br />    drop table chained_rows;<br />    /* Create the CHAINED_ROWS table */<br />    @?/rdbms/admin/utlchain<br />    set echo on<br />    spool fix_mig<br />    /* List the chained & migrated rows */<br />    analyze table &table_name list chained rows;<br />    /* Copy the chained/migrated rows to another table */<br />    create table migrated_rows as<br />    select orig.* from &table_name orig, chained_rows cr<br />    where orig.rowid = cr.head_rowid<br />    and cr.table_name = upper(’&table_name’);<br />    /* Delete the chained/migrated rows from the original table */<br />    delete from &table_name<br />    where rowid in ( select head_rowid from chained_rows );<br />    /* Copy the chained/migrated rows back into the original table */<br />    insert into &table_name select * from migrated_rows;<br />    spool off<br />    使用这个脚本时，必须将涉及到的外键约束去掉。<br />    7、索引重组<br />    在一个不稳定的表上建索引会影响性能，一个索引block只有完全空时才能进入free list，即使一个索引block里只含有一个条目，它也必须被维护，因此索引需要进行阶段性的重建。<br />    1）检查索引是否需要重组<br />    A、收集一个index的使用统计<br />    ANALYZE INDEX acct_no_idx VALIDATE STRUCTURE;<br />    B、查看收集的统计数据<br />    SELECT NAME,(DEL_LF_ROWS_LEN/LF_ROWS_LEN) * 100 AS index_usage FROM index_stats;<br />    Column Description <br />    LF_ROWS Number of values currently in the index <br />    LF_ROWS_LEN Sum in bytes of the length of all values <br />    DEL_LF_ROWS Number of values deleted from the index <br />    DEL_LF_ROWS_LEN Length of all deleted values <br />    C、如果浪费超过20％则索引需要重建<br />    ALTER INDEX acct_no_idx REBUILD;<br />    D、或者对索引进行整理<br />    Alter index acct_no_idx coalesce;<br />    2）标记未使用的索引<br />    A、 开始监测索引的使用<br />    Alter index hr.emp_name_ix monitoring usage;<br />    B、 停止监测索引的使用<br />    Alter index hr.emp_name_ix nomonitoring usage;<br />    C、 查询索引的使用情况<br />    Select index_name,used from v$object_usage;<br />    删除未使用过的索引，可以降低DML操作的成本，从而提升系统性能。<br />    为了尽可能经济的利用block，应对存在较多空block、镜像行的表进行重建，对建立不稳定表上的索引应有规律的进行重建，并尽可能创建本地管理的表空间。<br />九、SQL优化<br />    1、优化器模式<br />    Oracle9i有两种优化器模式可以选择：<br />    ? Rule-based:<br />    – Uses a ranking system<br />    – Syntax- and data dictionary–driven<br />    ? Cost-based:<br />    – Chooses least-cost path<br />    – Statistics-driven<br />    Rule-based模式满足向后兼容，而Cost-based模式中的成本大部分来自于逻辑读的次数，推荐使用Cost-based模式。<br />    2、固定optimizer plan<br />    1）概念<br />    对于每一个查询，optimizer都会准备一个定义了操作执行顺序和方法的操作树（执行计划），oracle server根据这个执行计划执行语句。通过固定执行计划，可以强制应用通过一种理想的方式访问数据，并且一个稳定的执行计划可以经历数据库的变化而保持不变。固定执行计划通过创建stored outline实现，outline使用cost-based的optimizer，因为其由一系列的hints组成。<br />    执行计划的固定依赖于当判定一个查询是否存在stored outline时查询语句是否完全一致，与判定shared pool里一个执行计划是否可以重用时的匹配方式是一致的。<br />    Outline被保存在outln schema中。<br />    2） 创建stored outline<br />    alter session set CREATE_STORED_OUTLINES = train;<br />    create or replace OUTLINE co_cl_join<br />    FOR CATEGORY train ON<br />    select co.crs_id, ...<br />    from courses co，classes cl<br />    where co.crs_id = cl.crs_id;<br />    stored outline通过category组织，相同的sql语句可以在多个category同时拥有stored outline，如果categoey没有指定，缺省是default category。<br />    当CREATE_STORED_OUTLINES等于true或category名时，oracle会为所有被执行的sql语句创建stored outline，也可以通过create outline手工创建。<br />    3） 使用stored outline<br />    将USE_STORED_OUTLINES设置为true或category名。<br />    alter session set USE_STORED_OUTLINES = train;<br />    当为一个查询寻找stored outline时，查询语句与stored outline里的语句必须完全一致，在outline里的hints也必须在查询语句中出现。<br />    3、private outline<br />    Private outline是当前保存的stored outline的副本，可以被编辑而不影响正在运行的系统，一个private outline只能被当前session看到，它的数据被保存在当前被解析的schema里。，知道显示的将其公布。<br />    当USE_PRIVATE_OUTLINES=TRUE时，一个已有outline的sql被提交时，optimizer会检查是否存在private outline，如果不存在，optimizer就不使用optimizer编译语句，而不会去检查公布的stored outline。<br />    4、在sql中使用hints<br />    Create index gen_idx on customers(cust_gender);<br />    Select /*+ index(customers gen_idx)*/<br />    Cust_last_name,cust_street_address,cust_postal_code<br />    From sh.customers where upper(gender)=’M’;<br />    5、EXPLAIN PLAN<br />    可以不通过tracing，需要建立plan_table表：<br />    Sql>@oracle_home/rdbms/admin/utlxplan;<br />    建立explain plan：<br />    Explain plan for select last_name from hr.emp;<br />    查询plan_table中的explain plan，可以直接查询，也可以通过脚本utlxplx.sql(隐藏并行查询信息)、utlxplp.sql（显示并行查询信息）查询。<br />    6、管理统计信息<br />    利用analyize命令收集或删除信息。<br />    参数：<br />    Compute：统计精确的数据；<br />    Estimate：估计的统计数据。<br />    各类统计数据的位置：<br />    表：dba_tables;<br />    索引：dba_indexes;<br />    列：user_tab_col_statistics;<br />    柱状图（histogram）详细的描述了一个特定列中数据的分布情况，可以通过analyize table ... for columns... 命令创建，保存在dba_histogram/dba_tab_histograms中。<br /><br />十、操作系统优化和使用资源管理器<br />    1、操作系统优化<br />    1）概念<br />    操作系统优化时应该考虑的因素有：内存的使用；Cpu的使用；IO级别；网络流量。各个因素互相影响，正确的优化次序是内存、IO、CPU。<br />    操作系统使用了虚拟内存的概念，虚拟内存使每个应用感觉自己是使用内存的唯一的应用，每个应用都看到地址从0开始的单独的一块内存，虚拟内存被分成4K或8K的page，操作系统通过MMU（memory management unit）将这些page与物理内存映射起来，这个映射关系通过page table控制。<br />    Raw device是没有文件结构或目录结构的磁盘或磁盘分区，由于它忽略了操作系统缓存，在某些情况下可以显着提升性能，但是在windows NT下，由于操作系统IO操作本身不使用文件系统缓存，所以raw device不能显示性能上的优点。<br />    2）Guideline<br />    CPU的最高使用率：90％；<br />    OS/USER进程数之比：40/60；<br />    各个CPU的负载应该大致均衡。<br />    3）服务器安全性检查<br />    A、检查UNIX系统用户口令<br />    检查：/etc/passwd、/etc/shadow，UNIX密码采用了shadow机制，安全性能高<br />    建议：参考UNIX命令passwd，修改/etc/default/passwd文件的某些设置如MAXWEEKS、MINWEEKS、PASSLENGTH使口令修改更加合理化。<br />    建议：定期更改UNIX系统的如下用户口令：<br />    root、oraprod、applprod、appprod<br />    B、检查 Remote Login<br />    启动了rlogin，服务器数据库a、数据库b、数据库c，终端console1、console2、console3及T3形成相互非常信任的关系，用户只要拥有一个服务器的超级权限就可以rlogin到.rhosts指明的任一主机而无需要口令。<br />    建议：非常不安全，参考UNIX命令rlogin和/目录下的文件.rhosts。在正式环境服务器和测试环境服务器之间不要建立这种远程信任的机制。<br />    C、检查FTP服务<br />    检查可以FTP到服务器的用户（/etc/ftpusers），注释了root用户，就是说用户可以用root权限FTP到服务器上。权限太大。<br />    建议：把这种权力取消，将/etc/ftpusers中root的注释符号（#）去掉，在列表中添加oraprod、applprod、appprod等用户使之不能FTP服务器。必要时（如上传PATCH时）再打开applprod的FTP权限。<br />    D、建议：UNIX系统管理员定期检查/var/adm下的messages、sulog；/etc/syslog.conf 等信息。检查是否有非法用户登陆UNIX。<br />    建议：与UNIX工程师探讨更好的监控方式<br />    4）数据库与应用产品安全性检查<br />    A、建议：修改oracle用户根目录下的.profile文件，修改该文件的权限为500。即使得用户登陆时并不执行和数据库或应用相关的环境变量，增加安全性。<br />    B、检查数据库DBA权限的用户密码和应用系统用户密码：SYSTEM、APPS密码都已经改变，SYS密码还是初始安装密码Change_on_install<br />    建议：立即修改SYS用户密码，定期更改APPS、SYSTEM、SYS密码。<br />    C、定期检查并清除$ORACLE_HOME/admin/bdump目录下的alert_PROD.log文件和后台进程trace文件。定期清除$ORACLE_HOME/admin/udump目录下的trc文件。<br />    D、建议：给应用产品登陆的用户设置口令过期限制，如口令访问次数限制或时间（天数）限制。<br />    建议：不要给使用应用产品的用户共享用户名和口令，每个用户分配一个应用产品用户名。<br />    建议：对有应用系统管理员权限的用户登记，不适合有系统管理员权限的用户要把权限回收，统一管理。<br />    E、定期检查并清除与Apache Server有关的log文件，目录为:<br />    /u01/prodora/iAS/Apache/Apache/logs/acccess_log、error_log<br />    /u01/prodora/iAS/Apache/Jserv/logs/jserv.log、mod_jserv.log<br />    F、定期检查清除listener、tnsname的log文件，文件存放在:<br />    /u01/prodora/8.0.6/network/admin/apps_prod.log、<br />    /u01/proddb/8.1.7/network/admin/prod.log<br />    /u01/proddb/8.1.7/network/log/listener.log、sqlnet.log…<br />    G、数据库控制文件做多个镜像，放在多个磁盘位置，提高安全性。<br />    5）网络安全性检查<br />    检查$ORACLE_HOME/dbs/initPROD.ora文件<br />    #remote_login_passwordfile=EXCLUSIVE<br />    设置为REMOTE_LOGIN_PASSWORDFILE=NONE，不允许远程客户用INTERNAL方式登陆。<br />    2、资源管理器（Resource Manager）<br />    通过资源管理器可以管理混合工作负载，控制系统性能。数据库资源管理器包括：<br />    ? Resource plans：包括 resource plan directives, 它指定了被分配到各个 resource consumer group的资源。<br />    ? Resource consumer groups：定义了具有类似资源使用需求的一组用户。<br />    ? Resource plan directives：包括下列内容:为consumer groups 或 subplans 指定resource plans；在各个 consumer groups 或资源计划的subplans 分配资源。
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/147287#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 10 Dec 2007 15:43:55 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/147287</link>
        <guid>http://ordier.javaeye.com/blog/147287</guid>
      </item>
      <item>
        <title>oracle索引的5种使用模式</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/147264" style="color:red;">http://ordier.javaeye.com/blog/147264</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          索引的使用对数据库的性能有巨大的影响。<br />共有五类不同的使用模式。<br /><br />1。INDEX UNIQUE SCAN    效率最高，主键或唯一索引<br />2。INDEX FULL SCAN      有顺序的输出，不能并行读索引<br />3。INDEX FAST FULL SCAN  读的最块，可以并行访问索引，但输出不按顺序<br />4。INDEX RANGE SCAN      给定的区间查询<br />5。INDEX SKIP SCAN       联合索引，不同值越少的列，越要放在前面<br /><br />--实验后的总论。<br />能用唯一索引，一定用唯一索引<br />能加非空，就加非空约束<br />一定要统计表的信息，索引的信息，柱状图的信息。<br />联合索引的顺序不同，影响索引的选择，尽量将值少的放在前面<br />只有做到以上四点，数据库才会正确的选择执行计划。<br />conn system/manager<br />grant select any dictionary to scott; <br /><br />conn scott/tiger<br />drop table t1 purge;<br />create table t1 as select * from dba_objects;<br />analyze table t1 compute statistics;<br />create index it1 on t1(object_type);<br />set autot traceonly<br /><br />select distinct object_type from t1;<br />将是全表扫描，为什么不使用索引呢？因为索引中不能含有null值，<br />如果使用索引就可能产生不正确的结果。<br /><br />--增加非空约束<br />alter table t1 modify (object_type not null);<br />select distinct object_type from t1  ;<br />使用INDEX FAST FULL SCAN方式查找数据<br /><br />--<br />select  object_type from t1;<br />使用INDEX FAST FULL SCAN，因为不需要排序<br /><br />select  object_type from t1 order by 1;<br />使用INDEX FULL SCAN,因为要按照顺序输出<br /><br />select  object_type from t1 where object_type='TABLE';<br />使用INDEX RANGE SCAN<br /><br />--使用非唯一索引<br />create index i2t1 on t1(object_id);<br />select * from t1 where object_id=3762;<br />使用INDEX RANGE SCAN,因为数据库不知道是否唯一<br /><br />--使用唯一索引<br />drop index i2t1;<br />create unique index i2t1 on t1(object_id);<br />使用INDEX UNIQUE SCAN,因为数据库知道是唯一的<br /><br />--跳跃的扫描索引<br />create index i3t1 on t1(object_type,object_name);<br />select * from t1 where object_name='EMP';<br />select object_name from t1 where object_name='EMP';<br />使用INDEX SKIP SCAN，因为数据库知道可以跳过object_type,虽然object_name在第二个列。<br /><br />--联合索引的顺序不同，影响索引的选择，尽量将值少的放在前面<br />drop index i3t1;<br />drop index it1;<br />create index i3t1 on t1(object_name,object_type);<br />select * from t1 where object_type='TABLE';<br />计划为全表扫描。
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/147264#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 10 Dec 2007 14:51:43 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/147264</link>
        <guid>http://ordier.javaeye.com/blog/147264</guid>
      </item>
      <item>
        <title>sql语句 select count(*) from emp; 不使用索引问题</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/147253" style="color:red;">http://ordier.javaeye.com/blog/147253</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          自己在学习oracle优化课程的时候，想当然的以为count(*) 操作肯定是会走索引的。可是那天碰巧试试发现居然是全表扫描。<br />      这里把关于这个问题的解决的过程记录下来，以便以后查阅，也希望能给同时遇见这个问题的朋友一点帮助。<br /><br />－－打开执行计划<br />SQL> set autotrace traceonly<br />－－刚开使的查询计划<br />SQL> select count(*) from emp;<br /><br />Execution Plan<br />----------------------------------------------------------<br />   0      SELECT STATEMENT Optimizer=CHOOSE<br />   1    0   SORT (AGGREGATE)<br />   2    1     TABLE ACCESS (FULL) OF 'EMP'<br /><br /><br /><br /><br />Statistics<br />----------------------------------------------------------<br />          0  recursive calls<br />          0  db block gets<br />          3  consistent gets<br />          0  physical reads<br />          0  redo size<br />        376  bytes sent via SQL*Net to client<br />        503  bytes received via SQL*Net from client<br />          2  SQL*Net roundtrips to/from client<br />          0  sorts (memory)<br />          0  sorts (disk)<br />          1  rows processed<br /><br /><br />-- 使用 hints 仍然是全表扫描<br /><br />SQL> select /*+ index(PK_EMP) */ count(*) from emp;<br /><br /><br />Execution Plan<br />----------------------------------------------------------<br />   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1)<br />   1    0   SORT (AGGREGATE)<br />   2    1     TABLE ACCESS (FULL) OF 'EMP' (Cost=2 Card=82)<br /><br /><br /><br /><br />Statistics<br />----------------------------------------------------------<br />          0  recursive calls<br />          0  db block gets<br />          3  consistent gets<br />          0  physical reads<br />          0  redo size<br />        376  bytes sent via SQL*Net to client<br />        503  bytes received via SQL*Net from client<br />          2  SQL*Net roundtrips to/from client<br />          0  sorts (memory)<br />          0  sorts (disk)<br />          1  rows processed<br /><br />－－分析表<br />SQL> analyze table emp compute statistics;<br /><br />表已分析。<br /><br />－－ 再次执行 则开始走索引<br />SQL> select count(*) from emp;<br /><br /><br />Execution Plan<br />----------------------------------------------------------<br />   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1)<br />   1    0   SORT (AGGREGATE)<br />   2    1     INDEX (FULL SCAN) OF 'PK_EMP' (UNIQUE) (Cost=1 Card=14)<br /><br /><br /><br /><br />Statistics<br />----------------------------------------------------------<br />          0  recursive calls<br />          0  db block gets<br />          1  consistent gets<br />          0  physical reads<br />          0  redo size<br />        376  bytes sent via SQL*Net to client<br />        503  bytes received via SQL*Net from client<br />          2  SQL*Net roundtrips to/from client<br />          0  sorts (memory)<br />          0  sorts (disk)<br />          1  rows processed<br /><br />问题解决，但仍有许多需要解释一下的地方。<br /><br />1. rbo与cbo<br />   rbo是基于规则的，在rbo下需要程序员自己分析然后指定应该使用那一个索引效率更高，也就是要使用hints。 而在cbo是基于cost的，这样sql引擎会自己计算用那个索引的cost最小，然后选择该索引执行sql语句。但是cbo需要有表的统计信息。<br />    rbo是oracle早期版本7i的特性，8i，9i是即支持rbo也支持cbo的 但oracle 10g就只有cbo了，所以在10g中oracle会自己对表进行分析，并保存表的统计信息。<br />    所以在没有对表进行分析的时候 走 rbo， 分析过的表走 cbo<br /><br /><br />2. 索引中不能含有null值，如果建索引的列不是 not null的，那么索引将不被使用。<br /><br />其它索引不被使用的情况：<br />   1）当对同一个表的两个列（其中一个列为主键，一个列为索引） 进行比较时，索引有时不会被使用<br />   2）在where中出现 is null或者is not null时 索引不能被使用<br />   3）在where语句中存在有not function时 例：not in,not exist,&lt;>,>,&lt;等情形下索引不能被使用<br />   4）当使用了single-row function时 例nvl,to_char,lower等索引不能被使用<br />   5）当使用通配符号%或者_作为查询字符串的第一个字符时索引不会被使用
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/147253#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 10 Dec 2007 14:12:36 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/147253</link>
        <guid>http://ordier.javaeye.com/blog/147253</guid>
      </item>
      <item>
        <title>开源数据库 derby</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/146163" style="color:red;">http://ordier.javaeye.com/blog/146163</a>&nbsp;
          发表时间: 2007年12月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          开放源代码 Derby 数据库引擎为开发人员提供了一个用于轻量级数据库开发的强大工具。Derby 数据库基于文件系统，可以在不同平台之间移植。由于这个原因，通常的策略是在开发时创建数据库，并将数据库与二进制发布文件一起发布，而不是动态创建数据库。<br />  用于创建类似于access数据库的应用开发，但derby是平台无关的。<br />相关资料<a href="http://db.apache.org/derby/" target="_blank">http://db.apache.org/derby/</a>
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/146163#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 05 Dec 2007 13:36:23 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/146163</link>
        <guid>http://ordier.javaeye.com/blog/146163</guid>
      </item>
      <item>
        <title>oracle buffer cache的优化</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/145598" style="color:red;">http://ordier.javaeye.com/blog/145598</a>&nbsp;
          发表时间: 2007年12月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          配置和使用buffer cache<br /><br />通过以下两种方式调整大小：<br />V$DB_CACHE_ADVICE / buffer cache hit ratio <br />1) V$DB_CACHE_ADVICE:<br />当DB_CACHE_ADVICE＝on 时有效。列出各种估计的cache size 和对应的物理读。Size_FACTOR=1表示当前大小。<br />SELECT size_for_estimate, buffers_for_estimate, estd_physical_read_factor, estd_physical_reads<br />   FROM V$DB_CACHE_ADVICE<br />   WHERE name          = 'DEFAULT'<br />     AND block_size    = (SELECT value FROM V$PARAMETER WHERE name = 'db_block_size')<br />     AND advice_status = 'ON';<br /><br />2) buffer cache hit ratio<br />低ratio并不能暗示增加cache size可以提高性能。高ratio有时反而会让你误认为cache size已经足够大而满足要求了。比如：重复的扫描一些大表或索引。因为大表的全表扫描往往都是物理读，会人为的降低hit ratio。检查并优化buffer get 较大的sql，Cache 一些经常访问的数据。<br />Db_cache_size 是针对默认的db_block_size的，对于非标准的block，要特别指定DB_nK_CACHE_SIZE 参数。<br /><br />考虑Multiple Buffer Pools：<br />通常只使用default buffer pool就能满足应用。KEEP buffer pool 用来支持经常访问的segment。RECYCLE buffer pool用于不经常的大batch jobs，以防止其不必要的cache消耗。他们都使用LRU规则。通过V$BUFFER_POOL 得到各种pool 信息。<br /> 访问大segment的时候可以考虑：<br />1、 如果是索引，检查其是否selective，否则优化sql<br />2、 如果已经优化，则可以将其放入recycle cache中，这样就不会影响其他的segment。<br />3、 或者将一些小的热segment放入keep cache 中，这样可以减少cache buffer miss ratio<br /><br />KEPP POOL:<br />如果应用中有的segment （比如小表）经常被访问，所以希望其长期保留在buffer中不被因某种因素ageout，可以将其存储在keep pool中。给KP分配内存，需要设置DB_KEEP_CACHE_SIZE参数，是独立于default buffer的。<br />大小取决于你想keep的segment，可以通过V$BH查看segment所占用的buffer，或者通过DBA_TABLES.BLOCKS and DBA_TABLES.EMPTY_BLOCKS得到used blocks<br />The NOCACHE(默认值) clause has no effect on a table in the KEEP cache.( alter table t nocache;)<br />可以改变segment的storage( buffer_pool keep)，然后在dba_table.buffer_pool体现：<br /><br /><br />查看oracle缓存的命中率（大于90％）<br /><br />select 1 - ((physical.value - direct.value - lobs.value) / logical.value)<br /><br />"Buffer Cache Hit Ratio"<br /><br />from v$sysstat physical,v$sysstat direct,v$sysstat lobs,v$sysstat logical<br /><br />where physical.name = 'physical reads'<br /><br />and direct.name='physical reads direct'<br /><br />and lobs.name='physical reads direct (lob)'<br /><br />and logical.name='session logical reads';
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/145598#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 03 Dec 2007 14:29:37 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/145598</link>
        <guid>http://ordier.javaeye.com/blog/145598</guid>
      </item>
      <item>
        <title>oracle 数据提交之后如何闪回</title>
        <author>Ordier</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ordier.javaeye.com">Ordier</a>&nbsp;
          链接：<a href="http://ordier.javaeye.com/blog/145582" style="color:red;">http://ordier.javaeye.com/blog/145582</a>&nbsp;
          发表时间: 2007年12月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          当你对数据库的数据进行update后，并commit。 但是你马上又后悔了你所做的更改，或者你在做update的时候忘记了加where条件 致使大量的数据被更改。<br />  如果你的数据库是oracle9i那么就可以利用 9i的新特性闪回查询<br /><br />  首先查看系统参数看是否支持闪回查询<br />SQL> show parameter undo<br /><br />NAME                                 TYPE        VALUE<br />------------------------------------ ----------- ---------<br />undo_management                      string      AUTO<br />undo_retention                       integer     10800<br />undo_suppress_errors                 boolean     FALSE<br />undo_tablespace                      string      UNDOTBS1<br /><br />参数 undo_management 为 auto 表示可以<br />undo_retention  表示可以闪回的时间，默认为3 个小时。<br /><br />9i支持闪回查询的包：dbms_flashback <br />需要在非dba用户下，例如：system 进行操作<br /><br />SQL> execute dbms_flashback.enable_at_time(sysdate-1/24/3);<br />1/24/3：系统当前时间 的前8个小时的数据。<br />执行完成之后，在当前的session下进行查询就可以查到历史数据。<br />如果要回到原来的实时数据<br /><br />SQL> execute dbms_flashback.disable<br /><br />局限性<br /><br />1、闪回查询是基于SCN的，虽然我执行的是：<br /><br />DBMS_FLASHBACK.ENABLE_AT_TIME(to_date('2003-05-16 15:37:23'));<br /><br />但Oracle并不会精确的这个时间点，而是ROUND DOWN到最近的一次SCN，然后从这个SCN开始进行恢复。而Oracle 9i是每五分钟记录一次SCN的，并将SCN和对应时间的映射做个纪录。<br /><br />这正是上面我们进行恢复时少了一条的原因。因此如果使用DBMS_FLASHBACK.ENABLE_AT_TIME来进行恢复，为了避免恢复失败，我可以先等5分钟，然后再进行恢复。<br /><br />使用DBMS_FLASHBACK.ENABLE_AT_TIME进行恢复还有一个缺点，那就是在Oracle 9i中SCN和对应时间的映射信息只会保留5天，因此我们无法通过DBMS_FLASHBACK.ENABLE_AT_TIME来恢复5天前的数据。如果你想使用闪回查询来恢复5天前的数据，你必须自己来确定需要恢复的SCN，然后使用<br /><br />DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER(SCN_NUMBER); 来定位你的恢复时间点，下面是使用方法：<br /><br />15:58:58 SQL> VARIABLE SCN_SAVE NUMBER;<br /><br />16:13:43 SQL> EXECUTE :SCN_SAVE := DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER;<br /><br />PL/SQL procedure successfully completed.<br /><br />16:13:50 SQL> print SCN_SAVE;<br /><br />SCN_SAVE<br /><br />----------<br /><br />2.1202E+11<br /><br />16:28:34 SQL> execute DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER(:SCN_SAVE);<br /><br />PL/SQL procedure successfully completed.<br /><br />另外，在使用DBMS_FLASHBACK.ENABLE_AT_TIME前，你必须设定你的NLS_DATE_FORMAT的精确程度，Oracle默认的是精确到天，如果你不设定，像上面的例子你不会得到预期结果。<br /><br />2、如果你使用sysdate和DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER来获取时间点或者SCN值，你必须注意它们取得都是当前的时间点和SCN值。<br /><br />3、你只能在事务开始时进入闪回查询模式，如果之前有DML操作，则必须COMMIT。<br /><br />4、闪回查询无法恢复到表结构改变之前，因为闪回查询使用的当前的数据字典。
          <br/>
          <span style="color:red;">
            <a href="http://ordier.javaeye.com/blog/145582#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 03 Dec 2007 13:36:49 +0800</pubDate>
        <link>http://ordier.javaeye.com/blog/145582</link>
        <guid>http://ordier.javaeye.com/blog/145582</guid>
      </item>
  </channel>
</rss>