วันจันทร์ที่ 1 เมษายน พ.ศ. 2556

การสร้างเครื่องมือ ดู Key ใน L-File

การสร้างเครื่องมือ ดู Key ใน L-File (Logical)

จากบทความ  สร้างรายงาน  จะพบว่าต้องหา L-File (Logical File) ที่มี key ที่ตรงกับรายงาน    
ถ้าระบบงานมี
L-File จำนวนมาก  ก็จะเสียเวลา ค้นหา(พอสมควร)   การมีเครื่องมือที่ดีย่อมช่วยการทำงานได้รวดเร็วขึ้น (แต่ตอนสร้าง เสียเวลาเล็กน้อยน๊ะครับ)

ข้อจำกัด เครื่องมือดังกล่าว จะทำงานได้ดี  บนสภาพแวดล้อม  แบบนี้น๊ะครับ
- 1 Table มี 1 Member, 1 Record Format เท่านั้น
- สร้าง L-File  เหมือน P-File  แต่เพิ่ม Key  เข้าไปเท่านั้น
- การตั้งชื่อ File ทำคล้ายแบบนี้            SQL010p  (P-file) -> SQL010L1, SQL010L2, ...
               ไม่ได้สร้างจาก SQL0X0L1 ที่เกิดจากการ Join หลาย File SQL010p กับ SQL020p


ตย.1 ดูรายชื่อ Key ที่มีใน L-File  ผ่าน Spool  ป้อนคำสั่ง  (ที่สร้างเอง)  ตามนี้
klist sql010l*              
จะเกิด Spool
                  Device or                       Total   Current              
 Opt  File        Queue       User Data   Status  Pages     Page   Copies      
      QPRINT      PSUQ                     RDY        1                1     

ภายใน Spool จะเห็นแบบนี้ 
                             Display Spooled File                             
File  . . . . . :   QPRINT                           Page/Line   1/3          
Control . . . . .   W48                              Columns     48 - 125     
Find  . . . . . .                                                             
..5....+....6....+....7....+....8....+....9....+....0....+....1....+....2....+
 S T  O U T  * *                                         DATE 13/04/01  PAGE  
RECORD     KEY :                                                              
SQL010R1   L1PLAC L1DIVI L1OPEC L1EPNO                                         
SQL010R2   L1PLAC L1DIVI L1OPEC L1EDUC L1EPNO                                 
SQL010R3   L1PLAC L1DIVI L1OPEC L1SEX  L1EPNO                                 
SQL010R4   L1PLAC L1DIVI L1OPEC L1MARY L1EPNO                                  
                                                               ** END OF LIST   

ตอนนี้เราสามารถเลือก L-File ที่ตรงกับที่เราต้องการได้ง่าย  แล้ว

ตย.2 ดูรายชื่อ Key ที่มีใน L-File  ให้แสดง ที่หน้าจอ ป้อนคำสั่ง  (ที่สร้างเอง)  ตามนี้
klistw sql010l*              

KEY100W1         **  K L I S T  D I S P L A Y  O U T  **      4/01/13 10:39:29
                                                                              
 FILE       KEY   :  FILE       KEY   :  FILE       KEY   :  FILE       KEY   
-----------------   -----------------   -----------------   ----------------- 
SQL010L1   L1PLAC   SQL010L2   L1PLAC   SQL010L3   L1PLAC   SQL010L4   L1PLAC 
           L1DIVI              L1DIVI              L1DIVI              L1DIVI 
           L1OPEC              L1OPEC              L1OPEC              L1OPEC 
           L1EPNO              L1EDUC              L1SEX               L1MARY 
                               L1EPNO              L1EPNO              L1EPNO 

แนวการสร้าง Tool

การค้นหา  เราสามารถทำได้โดยเปิดดูผ่าน
(1) Source File   วิธีพื้นฐาน
(2) Object  ด้วยคำสั่ง DspFd  QGPL/SQL010L1


ตัวอย่างผลลัพธ์บางส่วน แสดงดังนี้
Record format . . . . . . . . . . . . . . . :            SQL010R1 
  Key field . . . . . . . . . . . . . . . . :            L1PLAC   
    Sequence  . . . . . . . . . . . . . . . :            Ascending
    Sign specified  . . . . . . . . . . . . :            UNSIGNED 
    Zone/digit specified  . . . . . . . . . :            *NONE    
    Alternative collating sequence  . . . . :            No       
  Key field . . . . . . . . . . . . . . . . :            L1DIVI   
    Sequence  . . . . . . . . . . . . . . . :            Ascending
    Sign specified  . . . . . . . . . . . . :            UNSIGNED 
    Zone/digit specified  . . . . . . . . . :            *NONE    
    Alternative collating sequence  . . . . :            No       
  Key field . . . . . . . . . . . . . . . . :            L1OPEC   
    Sequence  . . . . . . . . . . . . . . . :            Ascending
    Sign specified  . . . . . . . . . . . . :            UNSIGNED  
    Zone/digit specified  . . . . . . . . . :            *NONE     
    Alternative collating sequence  . . . . :            No        
  Key field . . . . . . . . . . . . . . . . :            L1EPNO    
    Sequence  . . . . . . . . . . . . . . . :            Ascending 
    Sign specified  . . . . . . . . . . . . :            UNSIGNED  
    Zone/digit specified  . . . . . . . . . :            *NONE     
    Alternative collating sequence  . . . . :            No        

การดูผ่าน Object น่าจะ  ถูกต้องกว่า

เทคนิคที่ใช้

ทำโดย  เปลี่ยนสิ่งที่เห็น  บนหน้าจอ ไปเป็น File  แล้วเขียนโปรแกรมอ่านจาก File ดังกล่าว
a. ป้อน  ชื่อ File (แบบ Generic) เช่น SQL010*
b. ค้นหา  รายชื่อ File ในกลุ่ม

            DSPOBJD OBJ(QGPL/SQL010*)   OBJTYPE(*FILE)   OUTPUT(*OUTFILE)   OUTFILE(QTEMP/B1)    


       ถ้า  กำหนดให้  ป้อน a เป็น P-File  สามารถหาได้ว่า  มี file อะไร  ที่เป็น L-File บ้าง   ด้วยคำสั่งชุดนี้
            DSPDBR FILE(QGPL/SQL010P)  OUTPUT(*OUTFILE)   OUTFILE(QTEMP/B2)    
    
    (ปรกติจะได้ ข้อมูลหลาย Row)  Loop อ่าน ข้อมูลจาก b. จะได้  Lib,File
    
เลือกเฉพาะ Attrbute ที่เป็น LF,LF38


            ชื่อ Field ดูได้จากคำสั่ง DSPFFD QTEMP/B     
               ODLBNM=Lib, ODOBNM=file, ODOBAT = "LF ", "LF38 ", ... (เพิ่มได้ตามต้องการ)
               อ่านทีละ File (Row) แล้วให้แสดงค่า key ใน file
               เช่น  ได้ค่า              ODLBNM=qgpl,  ODOBNM=SQL010L1


c. ดึงค่า Key ของ  Lib,File จาก b.


            DSPFD FILE(qgpl/SQL010L1)   TYPE(*ACCPTH)  OUTPUT(*OUTFILE)  OUTFILE(QTEMP/C)     


            ชื่อ Field ดูได้จากคำสั่ง DSPFFD QTEMP/C     
            APFTYP = File type (P=PF,L=LF), APKEYF = Key Field Name, APKEYN = Key Field Number
            นำค่า Key ที่ได้  บันทึกลง File

d. ทำโปรแกรม แสดงผลลัพธ์  ตาม ตย.1,2

ข้อแนะนำ ควรสร้างและทดสอบ c. ก่อน  แล้วจึงสร้าง b
            call   pgm-c  (Lib  File)

สร้าง Pgm-C

               call  Pgm-C  parm(Lib  File)
               Pgm-C  (เป็น CL-Pgm)
           กรณีนี้  ผมจะสร้าง File Output  (เพื่อใช้ตรวจสอบได้ง่าย)  อ้างอิงจาก ผลลัพธ์นี้  

               DSPFD FILE(&Lib/&File)   TYPE(*ACCPTH)  OUTPUT(*OUTFILE)  OUTFILE(QTEMP/C) 
               ดู field ด้วยคำสั่ง  dspffd qtemp/c
Source Code
qgpl/qddssrc    KeyFp
qgpl/qddssrc    KeyFL1
            APLib               10                   
            APFile              10                   
            APKSEQ            1                   
            APKEYF           10
            APLib               10
            APFile              10
            APKSEQ            1
            APKEYF           10
       K   APKSEQ
       K   APKEYF          


สร้าง P-file, L-File จาก Source Code ข้างต้น

           note ถ้าใช้ QTEMP/C ได้คล่อง  สามารถสร้าง L-file อ้างอิง Qtemp/C ได้เลย   ไม่ต้องสร้าง File Output

                      Pgm   Parm(&Lib  &File)
                      dcl     &File    *CHAR   10
                      dcl     &Lib     *CHAR   10

                      /*  บันทึก Key ใน L-File ลง file  */
                      DSPFD FILE(&Lib/&File)   TYPE(*ACCPTH)  OUTPUT(*OUTFILE)  OUTFILE(QTEMP/C) 

                      /*  ย้ายข้อมูล QTEMP/C ไป KeyFp  */
                      CPYF FROMFILE(QTEMP/C) TOFILE(GQPL/KeyFp) MBROPT(*ADD)    

                      EndPgm

               Tip          เพิ่ม  ตรวจสอบอื่นๆได้  เช่น  ตรวจสอบ Error (ไม่พบ File)
               ทดสอบ
                              (Clear Data ใน  qgpl/KeyFp ก่อน)
                              call   pgm-c  ('QGPL'  'SQL010L1')
                              call   pgm-c  ('QGPL'  'SQL010L2')
                              call   pgm-c  ('QGPL'  'SQL010L3')
                              ตรวจดู Data (ใช้อะไร ก็ได้ที่ง่ายๆ)

สร้าง Pgm-D  

ใช้ดูผลลัพธ์ (แบบ ตย.1)

            first# = 'Y'
            Read  KeyFL1
            ---------------------------------------------------------
            Loop Not EoF (End of File)

                        '---First time
                        If  first# = 'Y'  Then
                                    first# = 'N'
                                    O#File = k1file
                        End                 
                        If  chg-Grp  (O#File <> K1file)  Then
                                    Print     O#File, Array
                                    O#File = k1file
                                    Clear Array
                        End
                        Move  k1KSeq -> j#
                        Array(j#) = k1KeyF

                        Read  KeyFL1
            Next
            ---------------------------------------------------------
            If  first# = 'N'  Then
                        Print     O#File, Array
            End                 

สร้าง Pgm-B

เพื่อเรียกใช้  Pgm-C
            call  Pgm-B  (Lib   File) 

            Pgm   Parm(&wLib  &wFile)
            DclF    File(Qtemp/B)
            dcl     &File    *CHAR   10
            dcl     &Lib     *CHAR   10

            DSPOBJD OBJ(Lib/File)   OBJTYPE(*FILE)   OUTPUT(*OUTFILE)   OUTFILE(QTEMP/B)    
            /*  แสดงชื่อ File ทั้งหมดที่อยู่ในกลุ่ม  Generic Name */

   Stp010:
            /*  ชื่อ Record Format ดูได้จาก  DSPFD  QTEMP/B */
            RCVF       RCDFMT(QLIDOBJD)
            MONMSG     MSGID(CPF0864) EXEC(GOTO CMDLBL(END010))

            /*  เลือกเฉพาะ L-FIle เท่านั้น  */
            IF         COND((&ODOBAT *GE 'LF ') *AND (&ODOBAT *LE 'LF38')) THEN(DO)                          
                CALL PGM(pgm-C) PARM(&ODLBNM &ODOBNM)
            ENDDO                                                     

   End010:
            ENDPGM

สร้าง Command เรียกใช้ Pgm-B  

               (ไม่ขออธิบาย รายละเอียด น๊ะครับ)
               สร้างใน QCMDSRC  (รับส่ง ตัวแปร 2 ตัว)
               ขณะ Create ให้ไปเรียกใช้  Pgm-B  (ซึ่งรับ 2 ตัวแปรนี้)

สรุป

คงเห็นภาพการสร้าง Tool ขึ้นมาช่วยหา key ใน L-File กันได้บ้างแล้วน๊ะครับ
เทคนิคข้างต้น  สามารถนำไปใช้ได้กับ งานหลายประเภท    จะเรียกเทคนิคนี้ว่า API (Application Program Interface)  "ย่อมๆ"  เราใช้คำสั่งพื้นฐาน และหาทางติดต่อกับชุดคำสั่งของ OS  แต่ที่เรียกว่า "ย่อมๆ"  เพราะ  เราต้องเขียนโปรแกรมเองค่อนข้างมาก

ตัวคำสั่งแต่ละตัวจะเห็นข้อมูลปริมาณมาก  แต่ในการใช้งาน ผมได้เลือกใช้เฉพาะที่เข้าใจง่าย
ผู้อ่านสามารถเพิ่มรายละเอียดต่างๆ  ได้ตามสภาพแวดล้อมของตนเองได้  เช่น 
L-File Key มีการกำหนด Select/Omit  เป็นต้น

มาทำรายงานกัน


ตอนแรกคิดว่า จะไม่เขียนบทความนี้
แต่น้องที่บริษัทฯ ทักว่าถ้าทำงานได้เร็ว  (ท่อง โครงสร้างหลัก)  ให้เขียนไว้ให้ดูด้วย
(ปรกติ จะต้องเขียนบ่อยๆ จนจำได้เอง)

รายงานที่พบเห็นกันบ่อย

Section             Model      Grp      ItemNo              Qty
AAA                 M111       A        IT300               100
AAA                 M111       B        IT310               100
AAA                 M111       K        IT320               100
AAA                 M111       D        IT330               100
                        ---------------------------------------
                        ttl#2 M111                          400

AAA                 M222       I        IT500               100
AAA                 M222       F        IT510               100
AAA                 M222       G        IT520               100
                        ----------------------------------------
                        ttl#2 M222                          300
----------------------------------------------------------------
ttl#1 AAA                                                   700

BBB                 X444       A        IT360               100
BBB                 X444       B        IT360               100
BBB                 X444       D        IT362               100
                        ---------------------------------------
                        ttl#2 ttl X444                      300
BBB                 X555       I        IT550               100
BBB                 X555       F        IT552               100
                        ---------------------------------------
                        ttl#2  X555                         200
---------------------------------------------------------------
ttl#1 BBB                                                   500

===============================================================
Grand ttl                                                  1200

Summary by Group   
            A        200
            B        200
            K        100
            D        200
            I        200
            F        200
            G        100


รายงานในลักษณะข้างต้น  User มองเห็นต่อเนื่องกัน 1 ชุด
แต่สำหรับ IT แยกเป็น 2 ส่วนใหญ่  คือ  ส่วนบน  แสดงรายการอย่างละเอียด และ  ส่วนล่าง แสดงแบบสรุป
ส่วนบน  ข้อมูลเรียงตาม  Section, Model, ItemNo  (ไม่ใด้เรียงตาม Grp)
ถ้าจะใช้  ดูแล้วเข้าใจง่าย  ควรวาง Grp ไว้หลัง Item no

## ใช้ SQL  ##

SQL จะ run แล้วได้ data ที่พร้อมใช้งาน 1 ชุด  ใน ASP.net  จะ bind เข้ากับ  GridView
เราสามารถเขียน
RPG ใน Style นี้ได้  แต่ code จะยาวกว่า (ย้อนไปดู หัวข้อ RPG เรียกใช้ SQL ครับ)  สำหรับรายงานข้างต้น  ต้องเขียน 2 ชุด
A. SQL สำหรับ ส่วนบน
               SQL : Select  ..(a)..  From  Lib.File (b)   Where   (c)         Order by  (d)
               SQL : Select  ..(a)..  From  Lib.File (b1)   Left Join Lib.File (b2) on …  lWhere   (c)   Order by  (d)
               Tip          เพื่อความเร็ว    ใน Where  ต้องใช้ Field เหมือนใน Index
ข้อมูลควรจะเรียง  ตามที่ User เห็น (เข้าใจง่าย)
ขณะที่
Bind ต้องแทรก  พิมพ์ Sub-Total ด้วย
B. SQL สำหรับ ส่วนล่าง
               SQL : Select  (ax), sum    From  Lib.File (b)   Where   (c)              Group by (ax)   Order by  (d)

## ใช้  Tool  (เช่น Crytal Report, Run Query) ##

วิธีคล้ายกับ SQL พื้นฐาน  แต่มีตัวช่วย  สร้าง Sub Total เพียงแค่บอก  เลือก Field (ที่อยู่ใน Order by)
เนื่องจากการทำ Sub-Total   มักจะแสดงเมื่อเปลี่ยนกลุ่ม (ข้อมูลที่เรียงไว้ดีแล้ว)

## ใช้ RPG กับ DB2/400 ## 

1.         เลือก File หลัก  ที่มี Field เรียงลำดับเหมือนกับ รายงาน             ->หา  Logical-File
               ตย. ข้างต้น L-File เรียงตาม Sect,Model,ItemNo
               ถ้า L-File  ไม่มี,  "ขาด Field"  (เช่น  ไม่มี Model)  ต้องสร้าง L-File ใหม่
DB Design
จากความสัมพันธ์ (ER) จะพบว่า Model ไม่ควรจัดเก็บรวมกับ ItemNo ไว้ใน Physial File, Logical File  เดียวกัน  แต่การออกแบบใน DB2/400 ที่เขียนโดย RPG แบบดั้งเดิม จะต้องรวมกัน  ใช้วิธีนี้กันมาก
Q: ถ้ามี L-File หลายตัว  จะเลือกอย่างไร ?
A: เข้าไปดูที่ Source File (QDDSSRC) หรือ ดู object ด้วยคำสั่ง DSPFD
     ถ้ามี
L-File มากคงจะลำบากครับ   ควรสร้าง Tool มาช่วย  (จะอธิบายในครั้งต่อไป)

2.  เลือกเทคนิค  สำหรับ  รายงานส่วนล่าง
     2.1     ทุกครั้งที่สร้างรายงานส่วนบน 1 row  ให้คำนวณสร้าง รายงานส่วนล่าง  (เหมาะกับ  ข้อมูลที่เปลี่ยนแปลง ตลอดเวลา เช่น งานรับ/จ่าย   ทำให้  รวมค่าจากด้านบน = ด้านล่างเสมอ)เขียนยุ่งยากกว่า
     2.2     อ่านข้อมูลใหม่  เพื่อทำรายงานส่วนล่าง  (เลือก L-File ใหม่ที่เหมาะ)(เหมาะกับ  ข้อมูลที่ “ไม่เปลี่ยนแปลง”  เช่น ข้อมูลหลังปิดบัญชี  เป็นต้น)เขียนง่ายมากผู้เขียนมักเลือก  2.1  (เพราะใช้ได้กับทุกกรณี)
3.  เขียนโปรแกรม สำหรับ รายงานส่วนบน
        Loop อ่านข้อมูลจาก File หลัก
               ตรวจสอบ Filter เช่น ไม่แสดงข้อมูลที่ Qty = 0
               ตรวจสอบ ทำงานเฉพาะ ครั้งแรก
               ตรวจสอบ การเปลี่ยนกลุ่ม (เพื่อพิมพ์ Sub total, Clear ค่า, ตั้งค่าเริ่มต้นใหม่)
               ทุกครั้งที่อ่าน File หลัก 1 Row  ให้ไปอ่าน File รอง หรือ ส่วนขยาย  (เช่น  ItemName, Color)

สังเกต     การปรับแต่ง/แก้ปัญหา มักจะแยกเป็น 3 จุด คือ เริ่มต้น Loop, ใน Loop และ สิ้นสุดLoop
FAQ
Q1: เริ่มต้น (รอบแรก) Sub-total พิมพ์เกินออกมา  ... เพิ่มตัวเช็คว่าเคยพิมพ์ หรือยัง  (first#)
Q2: หลังเปลี่ยนกลุ่ม  ค่าไม่ถูก reset ... ใช้ตัวแปร เก็บค่าเก่า สำหรับเช็คเปลี่ยนกลุ่ม เช่น O#xxxx, T1Sum
Q3: หลังเปลี่ยนกลุ่ม  หลัก  ไม่พิมพ์  กลุ่มย่อย  ... ต้องพิมพ์กลุ่มย่อย ให้ครบ ก่อนจึงพิมพ์กลุ่มหลัก
Q4: หลังหมด data ไม่พิมพ์ Sub Total  … ต้องพิมพ์
Q5: ถ้าไม่มี data ต้องไม่พิมพ์ Grand Total … เพิ่มตัวเช็คว่าเคยพิมพ์ (ใช้ร่วมกับ Q1 ได้)

ตย.  Psudo Code ด้านล่าง  เขียนเป็น Template ที่ครอบคลุมปัญหาข้างต้น  (อาจจะดูยาวไปนิด)

fiest# = 'Y'
Key15     Setll        L-File                    
Key14     ReadE    L-File
Do While EoF, End of Key
               '---More Filter
               '----init  1st Time
               If   first# = Y'  Then
                              fiest# = 'N'
                              O#Itno = L1Itno
                              O#IModl = L1Modl
               End
               '---------------------------------------------------
               If  Chg-Lvl-1 (O#Modl <> L1Modl)  Then                               
                              Print  Total Lvl-1
                              O#Itno = L1Itno, T1Sum = 0
                              Print  Total Lvl-2
                              O#Modl = L1Modl, T2Sum = 0
               Else
                              If  Chg-Lvl-2 (O#Itno <> L1Itno)  Then                
                                             Print  Total Lvl-2
                                             O#Itno = L1Itno, T1Sum = 0
                              End
               End
               '---------------------------------------------------
               '---อ่าน File รอง  (เช่น ItemNo  -> File -> ItemName, Draw,Color, ...)
               Add      T1Sum, T2Sum
               Print Detail
               Key14     ReadE    L-File
End Do

if  first# = 'N' Then                              
               Print  Total Lvl-2
               O#Itno = L1Itno
               Print  Total Lvl-1
               O#Modl = L1Modl
               Print  Grand Total
End
Tip          ถ้าการเช็คเปลี่ยนกลุ่ม  มีขนาดมาก (เช่น Qty,Amt มี 8 field)  สามารถแยก code ที่ซ้ำๆกัน  ไปเป็น Sub-Routine 





วันอาทิตย์ที่ 24 มีนาคม พ.ศ. 2556

ไม่สร้าง Index File ใหม่ได้มั๊ย


ใครที่ต้องทำหน้าที่ DB-Admin บน DB2/400 ที่เขียนด้วย RPG (โดยไม่ใช้ SQL)
คงเคยมึนกับปัญหานี้

    Developer ต้องการสร้าง Index ใหม่เพื่อความรวดเร็วในการสร้าง report ที่มีการเรียงลำดับ
มีคนแซวว่า  แทบจะสร้าง 1 report ต่อ 1 index File กันเลย

Q:บริษัทคุณมีรายงาน (สร้างด้วย RPG ที่ไม่ใช้ SQL) กี่ตัว ?
ถ้าวันนี้มีถึง 1,000 report คุณน่าจะมี Index File มากเกิน 100 ตัวแล้ว


แล้วจะ "จัดการ" Index อย่างไรดี ? 
- เปลี่ยนการเขียน Report ไปติดต่อด้วย SQL (ด้วย Web, RPG)
- RPG ใช้ Work File แทนการสร้าง Index File ตัวใหม่ 
- RPG ใช้ Array แทนการสร้าง Index File ตัวใหม่ 
- ...

วันนี้เราจะพูดหัวข้อนี้ครับ  ใช้ Work File 
เหมาะกับคนที่ยังไม่พร้อมจะเรียนรู้ SQL หรือ การแก้ไขโปรแกรมที่มีอยู่ในลักษณะแก้ไขเล็กน้อย
(ไม่รู้น้อยจริงหรือเปล่า)


หลายคนคงแย้ง ว่า การจัดการ Index มีหลายเรื่องต้องคำนึง ... ผู้เขียนไม่เถียงครับ
(แต่เรื่องมันจะยาว และอ่านยากกว่านี้)

(ทบทวน) Index File 



การสร้าง Index เป็นการให้  เครื่องฯ (DB Engine) ทำการเรียงลำดับข้อมูล "ทันที
และจัดเก็บไว้ (รอการเรียกใช้)  

ข้อดี   การ SQL Data ปริมาณมาก ที่ีมีการ Filter (Where) จะทำงานเร็วขึ้น

ข้อเสีย
...จำบทการเรียงลำดับข้อมูล ตอนเรียนได้มั๊ยครับ (มันเข้าใจยาก พอสมควร)
   มันจะทำงานทุกครั้งที่ Field ที่เป็น Index (เพิ่ม/แก้ไข/ลบ) = ทำงานช้า

...รอการเรียกใช้ = ถ้าไม่ใช้งานมัน  ก็ทำงานแบบหนักฟรีไป

ลองนึกภาพตามนี้  

งานบันทึกที่มี 5 Users ป้อนงานกัน ต่อเนื่องทั้งวัน
(Call Center, งานบันทึกผลการผลิต, การส่งออก, ...)

- การป้อนแต่ละ 1 ครั้งที่มีผลต่อ  5 Table  ที่แต่ละตัวมี Index 10 ตัว  
... แสดงว่า แต่ละCPU ต้องทำ Index 250 ครั้ง

การสร้างรายงานด้วย RPG ใน 20 ปีที่ผ่านมา
- โปรแกรมเมอร์ ต้องไปค้นหาว่า เคยมีคนสร้าง Index File ที่ตรงกับรายงานที่เราจะสร้างด้วย RPG หรือไม่ ?

- ถ้ามี  ก็เรียกใช้
- ถ้าไม่มี  ก็สร้าง index file "ใหม่"

การทำงานมันยุ่งยากจน  บางคนได้สร้าง Utility เอาไว้ค้นหา Index File กันเลยน๊ะครับ
(สร้างได้ไม่ยาก)



ข้อสังเกต
- Index File ที่สร้างในช่วงแรก ค่อนข้างจะเป็น Index File ที่มีการใช้งานบ่อย เช่น เรียงตาม Year,Month  เป็นต้น

- Index File ที่สร้างในช่วงหลัง  มักจะเป็นงาน "เฉพาะ" ตามไอเดียของผู้ใช้  น๊ะเวลานั้นๆ
(ยุคนี้ เรียกว่าการทำ Adhoc Query) 




ตย.เช่น  เรียงตาม  อายุงาน(พนักงาน),  จำนวนคงเหลือ, คำอธิบายสินค้า, ...
(เมื่อสังเกตดู) จะเห็นว่า  เป็น Index ที่มีความถี่ของการใช้งานน้อยมาก
(อาจจะใช้งาน แค่ตอนสร้าง เท่านั้น)



ที่บริษัทฯผมทำงาน  แต่ละระบบงาน จะสร้าง Index กับ Table หลักไว้เฉลี่ย 10 ตัว ต่อ 1 Table 
(มากที่สูงคือ 63 ตัว  ... อ๊าก!)




ถ้าบริษัทฯ ใดเริ่มเปลี่ยนการสร้างรายงาน มาใช้ SQL (RPG กับ SQL, Web กับ SQL)

ก็แทบจะ "ไม่จำเป็นต้องสร้าง Index File ใหม่" (การเรียงลำดับ เกิดขึ้นใน SQL:Order By)
...บริษัทใด ยังไม่มีแผนฯ ควรเริ่มได้แล้วครับ


Tip การจะเลือกยกเลิก Index ใน MS SQL Server จะมี Tool:Query Optimize เป็น Log 
     ที่ตรวจว่ามีใครใช้ Index อะไรในช่วงเวลานั้น  เมื่อเทียบกับ Index ที่คุณมีทั้งหมด
     ก็พอจะรู้ได้ว่า ตัวไหนใช้น้อย/ไม่ใช้งานเลย 


เมื่อรายงานเริ่ม "ช้า" 


โดยไม่มีเหตุผลที่เหมาะสม (ไม่น่าจะช้าที่ Spec เครื่อง, ไม่ใช่โปรแกรมทำงานผิดปรกติ)
ถ้ามีงบฯ มักจะ Upgrade เครื่องใหม่ (คิดง่ายดี)
ถ้าไม่มีงบฯ - ทีม Architecture มักจะมาตรวจปัญหาพบ  กับงานกลุ่ม Index เป็นกลุ่มแรกๆ ที่ทำให้เครื่องช้า
เป็นงานตรวจที่ใช้เวลานาน และตรวจเสร็จแล้วใช้เวลาแก้ไขนาน (จนไม่มีใครอยากจะแก้ไข)


Tip ใน DB2/400 จะรู้ได้อย่างไรว่า SQL ทำงานช้าที่จุดไหน (กรณี Join หลาย File) ต้องใช้
     iSeries Navigator : Visual Explain ดูผลการทำงานใน SQL ของเรา
     ใน Visual Explain จะบอกให้รู้ว่า DB2 ผ่านขั้นตอนอย่างไร และ เสียเวลาทำงานในแต่ละจุด
     นานแค่ไหน
 เมื่อรู้ว่าจุดไหน"ช้า" ก็แก้ปัญหาซะ เปลี่ยน SQL, สร้าง Index ใหม่ในจุดนั้น



ตย. การเพิ่มความเร็วของเครื่อง (อาจจะต้องทำหลายเรื่องพร้อมกัน)
- "ยกเลิก" Index บางตัว  แล้วปรับ RPG มาใช้  แนวทางการทำงานของ SQL 
Select *  from File1 where Y/M = 2013/05 Order by อายุงาน
- "สร้าง"  Index ที่จำเป็นจริงๆ  บางตัว "ต้อง" มี  แต่มันไม่มี  เช่น  รายงาน 50% ต้องเรียง/เลือกโดย Field:Customer  แต่ Index ที่สร้างไว้ "ไม่มี" Field นี้


(ทบทวน) การทำงานของ SQL 
Select *  from File1 where Y/M = 2013/05 Order by อายุงาน

#1 ถ้าข้อมูลมี 1,000,000 rows  Filter จะเลือกข้อมูล โดยใช้ Index (ที่ใช้บ่อย) ตย.นี้คือ Y/M จะได้ ข้อมูลที่สนใจ  มาเพียง  1,000 rows
#2 จากนั้น จึงเรียงลำดับข้อมูลดังกล่าว    
จากข้อมูล 1,000,000 rows เรียงข้อมูลจริงเพียง 1,000 rows เท่านั้น

การใช้ Work File

ตย. สร้าง Index File เช่น WRK010p

Field-Key [100]
Field-Data [200]
กำหนดให้เรียงลำดับ ตาม Field-Key
(ตย. นี้ใช้ Physical File ที่มี Key)

#1: อ่านข้อมูล + Filter โดยใช้ Index -> จัดเก็บ Data ไว้
Read File1
Loop 
Age = อายุงาน
        UsId = รหัสพนักงาน
กรณีที่ Data มีปริมาณน้อย  จัดเก็บ Data ลงอ Field-Data
WrData = UserName
กรณีที่ Data มีปริมาณมาก  จัดเก็บ Primary Key ไว้ (เรียกใช้ภายหลัง)
                UsId = รหัสพนักงาน
Write  WRK010p
Read File1
End Loop

อาจจะใช้ Data Structure ช่วยจัดการ Field

#2: อ่านจาก Data ที่เลือกไว้ (เรียง) มาแสดงผล
Read WRK010p
Loop
กรณีที่ Data มีปริมาณน้อย - นำ Field-Data มาแสดงผลเลย
กรณีที่ Data มีปริมาณมาก - ใน Primary Key ไปค้นหาข้อมูลหลัก
Field-Data (Primary Key) -> File1  (อ้างอิง Index)
Print  
Read WRK010p
End Loop

#0: เพิ่มเติม
กรณีที่ ต้องเรียกใช้หลายเครื่องฯ พร้อมกัน  เราจะใช้เทคนิค สร้าง Object ไว้ใน Lib: QTEMP
ดังนี้


    Call CL-100  
                 CRTDUPOBJ OBJ(WRK010)  FROMLIB(QGPL)                                   OBJTYPE(*FILE)  TOLIB(QTEMP)  
                 Call RPG-111

สรุป

เราไม่ต้องสร้าง Index File ใหม่  ก็ได้  ด้วยความเข้าใจและเลือกใช้วิธีที่เหมาะสมถ้าใครยังคงเขียน RPG (แบบไม่ใช้ SQL) ก็คงต้องใช้เทคนิคนี้ วิธีที่อธิบายถือว่าเป็นทางเลือก  

สำหัรบแต่คนที่กำลัง กำหนดแนวทาง ผมเสนอให้ทำความเข้าใจและเลือกในทางที่เหมาะสม
ส่วนใครที่ใช้ RPG ด้วย SQL หรือ Web (ด้วย SQL) การสร้าง Index บางกรณีจะช่วยให้ทำเร็ว
รวมทั้ง  ทำให้คุณเลือก "สร้าง Index" ที่เหมาะสมน๊ะครับ