隨筆-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 閱讀(2116) | 評論 (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 閱讀(390) | 評論 (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 閱讀(693) | 評論 (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 閱讀(4731) | 評論 (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 閱讀(911) | 評論 (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 閱讀(9354) | 評論 (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 閱讀(6992) | 評論 (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 閱讀(645) | 評論 (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 閱讀(9069) | 評論 (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 閱讀(4008) | 評論 (0)編輯 收藏
          僅列出標題
          共32頁: First 上一頁 8 9 10 11 12 13 14 15 16 下一頁 Last 
          主站蜘蛛池模板: 平和县| 宁乡县| 霍邱县| 方正县| 兴国县| 天门市| 个旧市| 瑞金市| 高雄县| 潜山县| 汝南县| 梅州市| 隆德县| 中超| 惠安县| 富阳市| 淮安市| 宜城市| 明光市| 嘉定区| 舟山市| 苗栗市| 平安县| 南江县| 扬中市| 长子县| 盐池县| 禹州市| 镇宁| 盐源县| 镇平县| 阿勒泰市| 堆龙德庆县| 濉溪县| 镇宁| 安乡县| 万源市| 宁蒗| 辽中县| 固始县| 芦山县|