Monday, July 6, 2009

วิธีการ Migrate Character Set ที่เหมาะสม (ตอนที่ 1)

(แปลจากบางส่วนของ “Character Set Migration Best Practices", An Oracle White Paper January2005)

ทำไมต้อง Migrate?
การ Migrate Database Character Set บ่อยครั้งเกิดจากความต้องการที่จะให้ระบบฐานข้อมูลสามารถใช้ได้กับภาษาใหม่ เพราะการขยายตัวขององค์กรออกไปยังประเทศอื่น ในอดีตระบบเก่า ๆ ขององค์กรจะใช้ Character Set ที่มีข้อจำกัดในการรองรับภาษาอื่น ๆ เช่น ชุดตัวอักษร America 7-bit (ASCII)สามารถใช้ได้กับภาษาอังกฤษเท่านั้น ในขณะที่ในยุโรป ชุดตัวอักษร European 8-bit สามารถจะรองรับภาษาอังกฤษบวกกับตัวอักขระอื่น ๆ ที่ใช้กันในยุโรปอีกด้วย ในขณะที่ในเอเชีย จะต้องใช้ชุดตัวอักษรที่ประกอบด้วยมากกว่า 1 ไบท์ต่อตัวอักษร 1 ตัว การที่จำเป็นต้องมีหลายชุดตัวอักษรเช่นนี้เป็นข้อจำกัดในการที่จะทำให้ระบบฐานข้อมูลสามารถรองรับภาษาต่าง ๆ ได้ทั่วโลก นอกจากนี้การเปลี่ยนแปลงทางวัฒนธรรม (ทางภาษา) เช่นการรวมตัวของสหภาพยุโรป ซึ่งทำให้ความจำเป็นใช้ครื่องหมาย Euro (€) ไปทั่วโลก หรือการที่ระบบของเราต้องติดต่อกับระบบซึ่งมี Character Set อื่นที่ใหญ่กว่า เช่น เว็บไซท์บน WWW หรือแม้แต่ Windows Client ซึ่งใช้ Code Page 1252 ซึ่งมี Character Set ที่มีจำนวนตัวอักษรมากกว่า ASCII ก็ทำให้เกิดความจำเป็นในการ Migrate เช่นกัน หรืออีกเหตุผลหนึ่งก็คือความต้องการที่จะรวมข้อมูลที่เป็นภาษาที่แตกต่างกันลงบนฐานข้อมูลตัวเดียวกัน เช่นข้อมูลชุดหนึ่งต้องใช้ภาษารัสเซียน แต่อีกชุดหนึ่งต้องใช้ภาษาฝรั่งเศสเป็นต้น

การเลือกใช้ Character Set ชุดใหม่
เราอาจจะเลือกใช้ Character Set ตัวที่ตอบสนองความต้องการของเรา แต่ถ้าในอนาคตเกิดมีความต้องการภาษาอื่น ๆ เพิ่มเติมขึ้นมาอีก เราก็อาจจะต้องทำการ Migrate อีก ดังนั้นควรเลือก Character Set ที่สามารถรองรับความต้องการที่จะเกิดขึ้นในอนาคตได้อีกด้วย

Character Set ของระบบฐานข้อมูล จะเป็นอิสระจาก Characte Set ของระบบปฏิบัติการ เพราะ Oracle มีโครงสร้างในการจัดการเรื่องความแตกต่างกันของภาษาของตนเอง ตัวอย่างเช่น บน Windows ที่เป็นภาษาอังกฤษ คุณอาจจะรันฐานข้อมูลที่มี Character Set เป็นภาษาญี่ปุ่น อย่างไรก็ตามเมื่อเครื่อง Client ต้องการติดต่อกับฐานข้อมูล ระบบปฏิบัติการ (OS) ของ Client จะต้องรองรับ Character Set ภาษาญี่ปุ่นด้วยพร้อมทั้งฟอนต์ที่เหมาะสม และวิธีการนำข้อมูลเข้า วิธีการหนึ่งคือใช้ Client ที่มี OS เป็นภาษาญี่ปุ่นในการติดต่อกับระบบฐานข้อมูล ถ้าคุณเลือก Character Set ที่แตกต่างไปจาก OS ของ Client จะทำให้ Oracle จะต้องแปลง Characte Set ของ OS ตัวนั้นไปเป็น Database Character Set

เพื่อประสิทธิภาพที่ดีที่สุด เลือก Character Set ที่หลีกเลี่ยงการแปลงดังกล่าว และเลือกเอา Character Set ที่มีประสิทธิภาพที่สุดสำหรับภาษาที่ต้องการ การใช้ชุดตัวอักษรไบท์เดี่ยว (เช่น WE8ISO8859P1 หรือ TH8TISASCII เป็นต้น) จะให้ประสิทธิภาพที่ดีกว่าชุดตัวอักษรที่เป็นหลายไบท์ และใช้พื้นที่ในการเก็บน้อยกว่า แต่ในขณะเดียวกันชุดตัวอักษรแบบไบท์เดี่ยวก็มีข้อจำกัดในการรองรับภาษาที่หลากหลายในสิ่งแวดล้อมที่มี Client ที่ใช้ Code Page หรือชุดตัวอักษรที่หลากหลายแตกต่างกันในการทำงานกับฐานข้อมูลตัวเดียวกัน

การเลือกชุดตัวอักษรจำเป็นจะต้องพิจารณา OS ของเครื่อง Client และ Application ที่จะติดต่อกับฐานข้อมูล ชุดตัวอักษรของฐานข้อมูลจะต้องมีตัวอักษรครบทุกตัวที่ชุดตัวอักษร Client ใช้ ไม่เช่นนั้นอาจจะมีการสูญเสียข้อมูลได้ เช่น ถ้าคุณต้องการจะใช้ชุดตัวอักษร A (บน Client) กับฐานข้อมูลที่ใช้ชุดตัวอักษร B คุณจะต้องแน่ใจว่าชุดตัวอักษร A เป็น Subset ของชุดตัวอักษร B อย่างไรก็ตามถ้าเราต้องการใช้ตัวอักษรเพียงบางส่วนของชุดตัวอักษร A และบางส่วนนั้นก็เป็น Subset ของชุดตัวอักษร B ก็ไม่จำเป็นที่ทุก ๆ ตัวของชุดตัวอักษร A จะต้องเป็น Subset ของชุดตัวอักษร B

ยกตัวอย่างเช่น บาง Application อาจจะมี Client บางตัวเป็น WE8MSWIN1252 (ชุดตัวอักษรภาษาอังกฤษที่ใช้บน Windows) และบางตัวเป็น WE8ISO8859P1 (ชุดตัวอักษรภาษาอังกฤษที่ใช้ในยุโรป) ถ้าไม่มีการใช้ตัวอักษรเช่น เครื่องหมาย '€' กับ Application นี้การแปลงชุดตัวอักษรก็จะไม่สูญเสียข้อมูล การสูญเสียข้อมูลเกิดจากการที่ Oracle จะแปลงตัวอักษรใด ๆ ซึ่งไม่อยู่ในชุดตัวอักษร B ให้เป็นเครื่องหมายคำถาม หรือแปลงเป็นตัวอักษรที่มีลักษณะคล้ายกันในเชิงของภาษา เช่นตัว a (ตัว a ที่มี umlaut) อาจจะถูกแปลงเป็น 'a' ถ้าคุณต้องทำงานในลักษณะที่มีเครื่อง Client กระจายกันอยู่ในที่ต่าง ๆ (Distribute Environment) พยายามใช้ชุดตัวอักษรที่มีตัวอักษรอยู่ในกลุ่มเดียวกันเพื่อหลีกเลี่ยงการสูญเสียข้อมูล

ถ้า Client ทุกตัวใช้ชุดตัวอักษรเดียวกันทั้งหมด คุณควรจะใช้ชุดตัวอักษร (ของฐานข้อมูล) ที่เป็น Superset ของชุดตัวอักษรที่ใช้กับ Client เหล่านั้น หรือถ้า Client แต่ละตัวไม่ได้ใช้ชุดตัวอักษรเดียวกัน ชุดตัวอักษรของฐานข้อมูลก็ควรจะเป็น Superset ของชุดตัวอักษรของ Client ทุก ๆ ตัวรวมกัน

สรุปคือ การเลือกชุดตัวอักษรควรจะทำดังนี้
1) เลือกชุดตัวอักษรที่สามารถจะรองรับระบบได้ทั้งในปัจจุบัน และในอนาคต
2) ชุดตัวอักษรของฐานข้อมูล ควรจะต้องเป็น Superset หรือเทียบเท่ากับชุดตัวอักษรของระบบปฏิบัติการของ Client ทุกตัวรวมกัน

ทำไมการใช้ UNICODE จึงอาจจะเป็นทางเลือกที่ดีที่สุด?
Unicode เป็นชุดตัวอักษรที่กำหนดรหัสของแต่ละตัวอักษร (Code Point) ไว้เป็นสากล ซึ่งทำให้สามารถเก็บตัวอักษรในทุก ๆ ภาษาในโลกไว้ได้ทั้งหมดในชุดตัวอักษรเดียว โดยไม่มีข้อจำกัดเรื่อง Platform (เช่น Unix, Linux หรือ Windows), โปรแกรม หรือภาษา ซึ่งทำให้เราสามารถที่จะพัฒนา, ติดตั้ง และเก็บภาษาต่าง ๆ ภายในฐานข้อมูลตัวเดียวกัน

ปัจจุบัน Unicode กลายมาเป็นมาตรฐานของซอฟต์แวร์ต่าง ๆ และเป็นชุดตัวอักษรที่มีการใช้กันอย่างมากมายในการแปลงข้อมูลจากระบบสมัยเก่า (Legacy System)

บน Oracle นั้น Unicode ถือเป็นชุดตัวอักษรขนาดใหญ่ที่สุดที่เป็น Superset ของทุก ๆ ชุดตัวอักษรที่ Oracle รองรับ จึงทำให้ Unicode เป็นชุดตัวอักษรที่เหมาะสมมากในการที่จะเป็นชุดตัวอักษรปลายทางที่ถูกแปลงมาจากชุดตัวอักษรอื่น สำหรับการติดตั้งระบบใหม่ๆ Oracle แนะนำให้ใช้ Unicode เสมอ

ในแง่ของประสิทธิภาพ ฐานข้อมูลที่เป็น Unicode บน Oracle10g อาจจะทำให้ประสิทธิภาพลดลงไปได้ถึง 10% เมื่อเทียบกับชุดตัวอักษรแบบไบท์เดี่ยว และอาจจะมากกว่าถ้ามีการใช้ String Function (เช่น Substring, Instring เป็นต้น) จำนวนมาก

Unicode ยังจำเป็นเมื่อมีการใช้ภาษาบางภาษาร่วมกับภาษาอื่น ๆ เช่นภาษาที่เป็นภาษาตัวเขียน (Scripts) เช่น Latin หรือ Cyrillic เมื่อมีการใช้ภาษาเหล่านี้ร่วมกันกับภาษาอื่น ๆ ทำให้มักจะต้องใช้ Unicode เสมอ ผู้สนใจอาจจะหาข้อมูลเพิ่มเติมได้ที่
1) "Oracle Unicode Database Suport" ซึ่งหาได้จาก Home Page
http://www.oracle.com/technology/tech/globalization/index.html

การใช้ Unicode Datatype (แทนที่จะเป็น Unicode Database ดังได้กล่าวมาแล้ว)
อีกทางเลือกหนึ่งของการเก็บข้อมูลในฐานข้อมูลเป็น Unicode คือการใช้ Datatype ที่เป็น NCHAR ซึ่งตัวอักษรที่เป็น Unicode สามารถนำมาเก็บไว้ในคอลัมน์พวกนี้ได้โดยไม่ต้องคำนึงถึงชุดตัวอักษรของฐานข้อมูล (เริ่มมาตั้งแต่ Oracle9i ชนิดข้อมูล NCHAR ถูกใช้เก็บข้อมูลที่เป็น Unicode เท่านั้น) NCHAR รองรับชุดตัวอักษร (Unicode) สองแบบคือ UTF-16 และ UTF-8

ถ้าคุณต้องการให้ระบบของคุณรองรับได้หลายภาษาในบางคอลัมน์เท่านั้น คุณสามารถเพิ่มคอลัมน์ชนิด NCHAR ในตารางเดิมที่ไม่ได้เป็น Unicode หรือในตารางใหม่ภายหลังก็ได้ คุณสามารถ Migrate ข้อมูลจากคอลัมน์ชนิด CHAR ไปเป็น NCHAR โดยใช้คำสั่ง ALTER TABLE MODIFY COLUMN
เช่น
SQL> alter table emp modify (enam NVARCHAR2(10));
การใช้ NCHAR มีประโยชน์ในด้านอื่น ๆ ด้วย กล่าวคือ
1) คุณสามารถใช้ NCHAR ในฐานะที่เป็นข้อมูล Unicode ได้ ในการสร้าง Application ให้กับลูกค้า
2) คุณต้องการให้ระบบฐานข้อมูลของคุณมีสิ่งแวดล้อมเหมือนกับสิ่งแวดล้อมของโปรแกรมเดิมที่เป็น UCS-2 หรือ UTF-16
3) คุณต้องการประสิทธิภาพที่ดีที่สุดที่เป็นไปได้ ถ้าฐานข้อมูลเดิมเป็นแบบไบท์เดี่ยว จงใช้คอลัมน์ NCHAR เพิ่มเติมสำหรับข้อมูล Unicode (แทนที่จะ Migrate ทั้งฐานข้อมูลให้เป็น Unicode)

NCHAR สามารถใช้ร่วมกับชนิดข้อมูลอื่น ๆ ได้ เมื่อมีการใช้หรือมีการ Operation กับชนิดข้อมูลอื่น คุณสามารถทำ Conversion แบบโดยตรง (Explicit) หรือแบบอ้อม (Implicit) ได้ โดยทางอ้อมคุณสามารถเก็บ, นำมาแสดง หรือทำกระบวนการใด ๆ กับ NCHAR ในทำนองเดียวกับชนิดข้อมูล CHAR ได้ และสามารถทำกับ DATE, NUMBER, ROWID, RAW และ CLOB ได้เช่นเดียวกัน โดยปกติแบบอ้อม Oracle จะทำการแปลงให้หากมีการทำ Operation กับข้อมูลที่มีชนิดข้อมูลต่างกัน
ในทางกลับกัน Explicit สามารถควบคุมได้มากกว่า คุณสามารถระบุว่าต้องการแปลงไปเป็นชนิดข้อมูลใด ตัวอย่างฟังก์ชั่นที่ใช้ในการแปลงเช่น
TO_NCHAR(), TO_CHAR(), TO_CLOB(), TO_NCLOB(), TO_NUMBER(), TO_DATE(), UNISTR(), ASCIISTR(), ROWIDTONCHAR(), CHARTOROWID()
อ่านข้อมูลเพิ่มเติมได้ที่:
1) "Migration to Unicode Datatypes for Multilingual Databases and Applications in Oracle9i" ใน Globalization Support โฮมเพจ
http://www.oracle.com/technology/tech/globalization/index.html

สิ่งที่ต้องคำนึงถึงในการ Migrate
1) ช่วงเวลาที่ระบบจะใช้งานไม่ได้อันเนื่องจากการปิดระบบเพื่อ Migrate (Downtime) จะต้องน้อยที่สุด และมีแผนสำรองหากมีปัญหาเกิดขึ้น บางที Downtime อาจจะเป็นเวลาไม่กี่ชั่วโมงไปจนถึงเป็นเวลาหลายวันแล้วแต่ความจำเป็นของระบบ
2) การสูญเสียข้อมูล ข้อมูลที่ได้ภายหลังจากการแปลงควรจะเหมือนกับตัวก่อนแปลง ควรจะคำนวณขนาดของข้อมูลหลังจากการแปลงไว้ก่อนด้วย โดยเฉพาะเมื่อแปลงไปยังชุดตัวอักษรที่เป็นหลายไบท์จะทำให้กินพื้นที่เพิ่มขึ้น
3) ประสิทธิภาพของฐานข้อมูลที่ใช้ชุดตัวอักษรใหม่ การแปลงชุดตัวอักษรแบบไบท์เดี่ยวไปยังไบท์เดี่ยว หรือชุดตัวอักษรแบบหลายไบท์ไปยังหลายไบท์จะไม่มีผลต่อประสิทธิภาพ แต่การแปลงชุดตัวอักษรจากไบท์เดี่ยว ไปยังหลายไบท์จะมีผลต่อประสิทธิภาพ

ข้อปฏิบัติก่อนแปลง
ก่อนจะทำการแปลงจะต้องรู้ขอบเขตของสิ่งที่ต้องทำก่อน จะต้องมีการทำการวิเคราะห์ข้อมูลเพื่อเช็คปัญหาที่อาจจะเกิดขึ้นได้ และประเมินว่าข้อมูลมากน้อยเพียงใดที่ต้องการแปลง

โปรแกรม Scanner ที่ใช้สแกนชุดตัวอักษร
ไม่ว่าจะเป็นการแปลงจากชุดตัวอักษรใดไปยังชุดตัวอักษรใด คุณจะต้องทำการ Pre-Scan ข้อมูลชุดนั้นก่อนเพื่อจะได้แน่ใจว่าการแปลงจะประสบความสำเร็จ Database Character Set Scanner เป็นโปรแกรมยูทิลิตี้ที่มีประสิทธิภาพในการสแกนฟิลด์ที่เป็นตัวอักษร และจะแสดงผลหรือแสดงประเด็นที่อาจจะเกิดขึ้นในการแปลง โดยมันจะจำลองการแปลงชุดตัวอักษร และแสดงผลเป็นรายงานสรุปผลการสแกน สิ่งที่ต้องทำในการแปลง และแนะนำชุดตัวอักษรปลายทางที่เหมาะสมที่สุด ผลของการแปลงอาจจะแบ่งได้เป็น 4 แบบคือ

Changeless (ไม่มีการเปลี่ยนแปลง)
ข้อมูลที่แปลง (ในเชิงไบนารี่) ไม่ได้มีการเปลี่ยนระหว่างตัวอักษรตัวต้นกับตัวปลายทาง เช่นตัว 'A' เมื่อเป็นไบนารี่คือ hex41 ที่ตัวต้นทาง เมื่อแปลงไปเป็นปลายทางก็ยังคงเป็น hex41 ดังนั้น 'A' ไม่มีการเปลี่ยนแปลงจากตัวต้นไปยังตัวปลายทาง ข้อมูลทั้งหมดจะต้องเป็นแบบ Changeless จึงจะสามารถใช้ สคริปต์ CSALTER (ใน Oracle Database10g) ได้อย่างปลอดภัย

Convertible (แปลงได้)
ข้อมูลตัวต้นทางสามารถถูกแปลงไปยังตัวปลายทางได้ เช่นถ้าต้นทาง 'A' เป็น hex41 แต่ตัวปลายทาง 'A' เป็น hex90 ข้อมูลทั้งหมดจะต้องอยู่ในแบบ Convertible หรือไม่ก็ Changeless โดยไม่มีการตัดแบ่งข้อมูลใด ๆ (Truncate) ก่อนที่จะใช้ Export-Import ยูทิลิตี้

Truncation (ข้อมูลถูกตัดแบ่งออก)
เมื่อมีการแปลง และข้อมูลปลายทางไม่สามารถรองรับข้อมูลจากต้นทางได้ เช่นเมื่อทำการแปลงจากชุดตัวอักษรแบบไบท์เดี่ยว Western European ไปเป็น Unicode, ตัวอักษรที่มี Accent จะถูกตัดแบ่งจาก 1 ไบท์ไปเป็น 2 ไบท์ ซึ่งทำให้ต้องมีการขยายคอลัมน์

Data Loss
เกิดขึ้นเมื่อชุดตัวอักษรปลายทางไม่มีตัวอักษรตัวที่อยู่ในชุดตัวอักษรต้นทางเช่นตัวยูโร (€) เป็นตัว hex80 ใน WE8MSWIN1252 แต่ไม่มีในชุดตัวอักษร WE8ISO8859P1 (Latin1) ซึ่งทำให้เกิดการสูญเสียข้อมูล

Data Truncation
Database Character Set Scanner จะทดสอบว่าข้อมูลหลังจากการแปลงจะสามารถเก็บลงในขนาดของคอลัมน์ปัจจุบันได้หรือไม่ ตัว Scanner จะชี้ให้เห็นว่าคอลัมน์ใดต้องทำการเปลี่ยนขนาด และแสดงข้อมูล 30 ไบท์แรกในคอลัมน์ ถ้าไม่ทำการแก้ไขข้อมูล หรือไม่เปลี่ยนขนาดของคอลัมน์จะทำให้เกิดการสูญเสียข้อมูลทั้งแถวระหว่างกระบวนการ Export-Import ในสถานการณ์ที่ปลายทางเป็นแบบหลายไบท์อาจทำให้เกิดสิ่งที่เรียกว่า Data Truncation เนื่องจากโดยปกติคอลัมน์ถูกกำหนดความกว้างเป็น Byte คอลัมน์ที่กำหนดเป็น VARCHAR(1) จะเก็บ 1 ตัวอักษรต่อ 1 Byte แต่จะไม่พอสำหรับชุดตัวอักษรแบบหลายไบท์ ตัวอย่างเช่น ตัวอักษรที่เป็น Unicode UTF-8 หนึ่งตัวอาจจะกินพื้นที่ 1-4 ไบท์เลยทีเดียว

แนวโน้มที่จะเกิดการ Truncate เมื่อแปลงไปเป็น UTF-8 ขึ้นอยู่กับภาษา เช่นถ้าฐานข้อมูลจะเก็บแต่ภาษาอังกฤษ โอกาสที่จะเกิดการ Truncate ก็มีน้อย และมีตัวอักษรสัญลักษณ์ไม่กี่ตัวที่จะถูก"ขยาย"จาก 1 ไบท์ไปเป็น UTF-8 ตัวอักษรยุโรปมักจะมีตัวอักษรท้องถิ่นที่จะต้องขยายไปเป็น 2 ไบท์เมื่อแปลงไปเป็น UTF-8 ตัวอักษรเอเชียเป็นตัวอักษรที่มักจะถูก Truncate มากที่สุดจากชุดตัวอักษรแบบดั้งเดิม (2 ไบท์) มาเป็น UTF-8 (3 ไบท์)

โอกาสที่จะเกิดมากขึ้นจากชุดตัวอักษรตะวันตกไปตะวันออกดังนี้
- English [£ ©] (1%)
- European [ä ß] (10%)
- Asian [佺俓來] (50%)

Data Loss
Export-Import ยูทิลิตี้ของ Oracle สามารถแปลงชุดตัวอักษรจากต้นฉบับมายังอีกชุดตัวอักษรหนึ่งได้ อย่างไรก็ตามผลที่ได้บางครั้งอาจจะมีการสูญเสียหรือเสียหายของข้อมูลได้ คุณจะต้องแน่ใจว่าข้อมูลต้นฉบับ"สะอาด" และตัวอักษรแต่ละตัวสามารถที่จะหาตัวแม็บได้ในอีกชุดตัวอักษร เช่นถ้าคุณกำลังแปลงจากชุดตัวอักษร A ไป B ชุดตัวอักษร B ควรจะเป็น Superset ของชุด A ชุดตัวอักษร B จะเป็น Superset ของชุดตัวอักษร A ก็ต่อเมื่อทุก ๆ ตัวของชุดตัวอักษร A มีอยู่ในชุดตัวอักษร B ตัวอักษรที่ไม่อยู่ในชุดตัวอักษร B จะถูกแปลงไปเป็นตัวอักษรแทน ซึ่งมักจะได้แก่ ? หรือเครื่องหมายคำถามแต่กลับหัว หรือตัวอักษรที่เกี่ยวเนื่องกับตัวอักษรที่ไม่มี เช่น ä สามารถถูกแทนด้วย 'a' ตัวอักษรแทนเหล่านี้ถูกกำหนดขึ้นที่ชุดตัวอักษรปลายทาง การสูญเสียข้อมูลอาจจะแตกได้เป็น 3 ประเภทคือ
1) สูญเสียข้อมูลตั้งแต่ต้นทางก่อนการ Migrate เช่นมีตัวอักษรที่ผิดปกติแต่ต้นทาง อาจจะมีการ Process ตัวอักษรผิดปกติ หรือข้อมูลมาจากชุดตัวอักษรอื่น (เช่นบน Client ที่มีชุดตัวอักษรคนละแบบกัน)
2) สูญเสียข้อมูลที่ปลายทาง เกิดขึ้นเมื่อไม่มีรหัสตัวอักษรที่เหมาะสมสำหรับชุดตัวอักษรปลายทางเพื่อแม็ปกับต้นทาง
3) สูญเสียข้อมูลจากการไป-กลับของการแปลง เกิดขึ้นเมื่อมีการแปลงจากชุดตัวอักษรต้นทางไปยังปลายทางได้อย่างถูกต้อง แต่เมื่อต้องการแปลงกลับจากตัวปลายทางมาเป็นตัวต้นทางอีกครั้งกลับได้ตัวอักษรคนละตัว
ดูเพิ่มเติมที่เรื่อง Why do Invalid Data Exception Occur? ข้างล่าง

สิ่งที่ต้องทำหลังการสแกน ก่อนการแปลง
เมื่อได้รัน Database Character Set Scanner แล้ว เราจะพบกับประเด็นต่าง ๆ ที่ต้องจัดการดังนี้

การจัดการกับ Exceptions
ขั้นแรกจะต้องพิจารณาข้อมูลที่ตกอยู่ใน Exceptions ประเภทใดประเภทหนึ่ง และตัดสินใจว่าจะจัดการกับมันอย่างไร

Truncation
เพื่อจัดการกับ Truncation เรามักจะขยายขนาดของคอลัมน์ ถ้าเราขยายขนาดของคอลัมน์เราจะต้องตัดสินใจว่าจะขยายขนาดให้ใหญ่พอที่จะรองรับขนาดของข้อมูลที่ใหญ่ที่สุดในคอลัมน์นั้นหลังจากการแปลง หรือขยายให้รองรับกับขนาดของคอลัมน์ตามกฎการแปลงจากชุดตัวอักษรหนึ่งไปยังอีกชุด เช่นถ้าเราต้องการแปลงจากคอลัมน์ที่เดิมเป็น CHAR(1) และใช้ชุดตัวอักษร 8859-1 ไปเป็น UTF-8 เราอาจจะขยายให้เป็น CHAR(4) (ขนาดของ 1 ตัวอักษรบน UTF-8 ที่ใหญ่ที่สุดคือ 4 ไบท์) เพื่อให้แน่ใจว่ามันจะสามารถรองรับตัวอักษรภาษาอะไรก็ได้รวมทั้งตัวอักขระพิเศษในอนาคต หรือถ้าเราแน่ใจว่าข้อมูลที่เราจะใช้ไม่มีทางเกิน 3 ไบท์แน่ ๆ และเรามีข้อจำกัดเรื่องพื้นที่ฮาร์ดดิสก์ เราอาจจะเลือกที่จะขยายให้เป็นแค่ CHAR(3) ก็ได้

เปลี่ยนวิธีการกำหนดขนาด(คอลัมน์)
เริ่มตั้งแต่ Oracle9i เราสามารถที่จะเปลี่ยนวิธีการกำหนดขนาดคอลัมน์ได้ โดยเฉพาะการเปลี่ยนวิธีการกำหนดขนาดเพื่อขยายขนาดคอลัมน์ให้รองรับการแปลงชุดข้อมูลไปเป็น Unicode UTF-8 วิธีการกำหนดขนาดคอลัมน์มีประโยชน์ในแง่การจัดการกับข้อความในคอลัมน์ และกำหนดขนาดพื้นที่ที่ต้องการของคอลัมน์สำหรับข้อความที่ใช้ตัวอักษรแบบหลายไบท์ และมีขนาดของตัวอักษรต่าง ๆ ไม่เท่ากัน (UTF-8 ใช้ไบท์เดียวสำหรับภาษาอังกฤษ, ใช้ 3 ไบท์สำหรับภาษาเอเชียส่วนใหญ่เป็นต้น) ในชุดตัวอักษรที่เป็นไบท์เดี่ยว จำนวนตัวอักษรกับจำนวนไบท์มักจะเท่ากันเสมอ ในขณะที่ในชุดตัวอักษรแบบหลายไบท์ หนึ่งตัวอักษร (หรือเรียกอีกอย่างว่า Code Unit) อาจจะประกอบด้วยหนึ่งไบท์หรือมากกว่า การคำนวณขนาดคอลัมน์เป็นไบท์เราเรียกว่า "Byte Sementics" ขณะที่การคำนวณขนาดคอลัมน์เป็นจำนวนตัวอักษรเราเรียกว่า "Character Semantics"
es ตัวอย่างเช่น ถ้าคุณแปลงฐานข้อมูลจากชุดตัวอักษร 8 บิท Western European Character Set ไปเป็น Unicode (AL32UTF8) สมมติว่าคุณมีคอลัมน์ที่เป็น VARCHAR2 ที่เก็บตัวอักษรที่เป็นสัญลักษณ์ท้องถิ่น ผลการสแกนจะระบุว่าคอลัมน์ (VARCHAR2) เหล่านี้จะต้องถูกเปลี่ยนขนาดเพื่อจะรองรับการขยายตัวไปเป็นฐานข้อมูลที่ใช้ชุดตัวอักษรแบบหลายไบท์ที่ใช้วิธีการกำหนดขนาดคอลัมน์แบบ Byte Semantics

และถ้าคุณต้องการจะเพิ่มภาษาเอเชียเข้าไปในฐานข้อมูล การใช้วิธีการกำหนดขนาดคอลัมน์แบบ Character Semantics สำหรับฐานข้อมูลหลังการแปลงอาจจะเป็นทางเลือกที่ดีที่สุด โดยเฉพาะเมื่อมีคอลัมน์แบบนี้จำนวนมากและชนิดของข้อมูลที่จะเก็บจะไม่เปลี่ยนแปลง ไม่อย่างนั้นถ้าเราใช้ Byte Semantics เราจะต้องขยายทุกๆ คอลัมน์เอง (เช่น ถ้าต้นทางเป็น VARCHAR2(4) ถ้าเราใช้แบบ Character Semantics เรายังคงสามารถใช้ VARCHAR2(4) ได้โดยไม่ต้องเปลี่ยนแปลง แต่ถ้าเราใช้ Byte Semantics เราอาจจะต้องกำหนดขนาดใหม่ตามขนาดที่อาจจะเพิ่มขึ้นเช่น อาจจะเป็น VARCHAR2(12) ถ้าเราคิดว่าแต่ละตัวอักษรจะขยายเป็น 3 ไบท์เป็นต้น

พารามิเตอร์เริ่มต้น (Initialization Parameter) ชื่อ NLS_LENGTH_SEMANTICS เป็นตัวกำหนดว่าคอลัมน์ที่เป็นตัวอักษรจะใช้ Byte หรือ Character Semantics ตอนที่มันถูกสร้างขึ้น ปกติ Byte Semantics เป็นดีฟอลต์สำหรับชุดตัวอักษรของฐานข้อมูล ส่วน Character Semantics เป็นดีฟอลต์สำหรับชนิดตัวอักษรแบบ NCHAR (ซึ่ง NCHAR จะใช้ได้กับการกำหนดแบบ Character Semantics เท่านั้น)

ทำไมจึงเกิด Invalid Data Exceptions?
ถ้ามีการสูญเสียข้อมูลเราจำเป็นต้องวิเคราะห์เหตุผลของการสูญเสีย การแก้ไขจัดการ Exception ถือเป็นการทำ Data Cleansing ข้อมูลที่ผิดปกติ (Invalid) อาจจะเกิดขึ้นได้เสมอเนื่องมาจากการตั้งพารามิเตอร์ NLS_LANG ที่ Client ไม่เหมาะสม และการ Conversion ระหว่าง Client กับ Server ก็ไม่ถูกต้อง ที่ถูกต้องแล้ว NLS_LANG ควรจะสอดคล้องหรือเป็นตัวเดียวกับ Code Page (ชุดตัวอักษร) ของ Operating System ยกตัวอย่างเช่น บน OS ที่เป็น Windows ภาษาอังกฤษ จะใช้ Code Page เป็น 1252 ซึ่งจะสอดคล้องกับชุดตัวอักษรของ Oracle ชื่อ WE8MSWIN1252 ถ้า NLS_LANG ถูกกำหนดไว้อย่างถูกต้อง ฐานข้อมูลจะสามารถแปลงข้อมูลที่เข้ามาจาก Client ได้โดยอัตโนมัติ แต่ถ้ากำหนดไม่ถูกต้องอาจจะทำให้เกิดการแปลงผิดได้สองกรณีคือ

1) เซ็ท NLS_LANG ต่างจาก OS Code Page และต่างจากชุดตัวอักษรของฐานข้อมูลด้วย
- ระหว่างการแปลงอาจจะมีตัวอักษรบน OS บางตัวที่ไม่สามารถแม็ปกับชุดตัวอักษรของ NLS_LANG ได้เลย ซึ่งก็จะทำให้ไม่สามารถแม็ปกับชุดตัวอักษรของฐานข้อมูลได้เช่นกัน กรณีนี้ฐานข้อมูลจะใช้ตัวอักษรแทน (เช่น ? เป็นต้น)
- ระหว่างการแปลงอาจจะมีตัวอักษรบน OS บางตัวแม้ว่าจะแม็ปกับรหัสชุดตัวอักษรของ NLS_LANG ได้ แต่เป็นคนละตัวอักษรกัน (รหัสตรงกัน แต่กลายเป็นคนละตัวอักษร) ตัวอย่างเช่น ตัว 'A' มีรหัสเป็น hex61 ใน Code Page บน Client (OS) แต่ 061 กลับเป็นเครื่องหมายเปอร์เซนต์ (%) ในชุดตัวอักษรของ NLS_LANG ในกรณีนี้การแปลงผิดจะเกิดขึ้น และข้อมูลจะถูกแม็ปไปเป็น '%' แทนที่จะเป็นตัวอักษร 'A' ดูภาพที่ 1



2) เซ็ท NLS_LANG ต่างจาก OS Code Page แต่ตรงกับชุดตัวอักษรของฐานข้อมูล ซึ่งเป็นกรณีที่เกิดขึ้นได้บ่อย ๆ เนื่องจากผู้ใช้งานคิดว่าจะต้องเซ็ท NLS_LANG ให้ตรงกับชุดตัวอักษรของฐานข้อมูลเท่านั้น โดยไม่คำนึงถึง OS Code Page เมื่อเป็นเช่นนี้ Oracle จะไม่ทำการแปลงใด ๆ ทั้งสิ้น โดยเหตุผลทางประสิทธิภาพ ซึ่งเราเรียกว่า Pass-Thru ผลที่ได้คือข้อมูล (ที่ไม่ได้ถูกแปลงเลย) จะถูกเก็บด้วยรหัสตัวอักษรบนฐานข้อมูลที่ไม่ตรงกับบน OS เลย ซึ่งก็คือข้อมูลขยะดี ๆ นี่เอง ที่น่ากลัวก็คือ ถ้ามองดูจาก OS บน Client ข้อมูลอาจจะดู OK เนื่องจากข้อมูลที่ผ่านจากฐานข้อมูลมา Client จะถูกแสดงออกมาโดยไม่ถูกแปลงเช่นกัน การ Pass-Thur ในลักษณะนี้เหมือนกับการครอบข้อมูลที่ถูกเก็บอย่างไม่ถูกต้องในฐานข้อมูล



(ยังไม่จบนะครับ ยังมีตอนต่อไป...ขอขอบคุณที่ให้ความสนใจและโปรดติดตามตอนต่อไปนะครับ)

3 comments:

The Knowledge Boxs said...

ขอบคุณครับ
ผมจะรอตอนต่อไปครับ

Leo said...
This comment has been removed by a blog administrator.
Unknown said...

ได้คำตอบอย่างกระจ่างแจ้ง แถมได้ความรู้อื่นๆเพิ่มขึ้นด้วย ขอบคุณมากครับ

Post a Comment