ลบข้อมูลหลายๆแสนระเบียน ใช้เวลานานมาก
กระทู้เก่าบอร์ด อ.Yeadram

 4,035   13
URL.หัวข้อ / URL
ลบข้อมูลหลายๆแสนระเบียน ใช้เวลานานมาก

ขอเรียนถามอาจารย์ทุกท่านนะคะ

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

แต่พอทดลอง ลบข้อมูลทั้งหมดออก ปรากฏว่าใช้เวลานานมากๆ(หลายนาที) ดื่มกาแฟหมดแก้วแล้วยังลบไม่เสร็จเลย

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

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

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

ขอขอบคุณนะคะ

13 Reply in this Topic. Dispaly 1 pages and you are on page number 1

1 @R05290
แก้ได้แล้วค่ะ หนูลองมั่วเล่นไปเรื่อยๆ จนแก้ได้ดังนี้ค่ะ

ใส่บรรทัดคำสั่ง DoCmd.SetWarnings False ไว้ข้างหน้า
และใส่ คำสั่ง DoCmd.SetWarnings True ปิดท้ายค่ะ

Private Sub Command0_Click()

            DoCmd.SetWarnings False
            DoCmd.RunSQL "delete * from [Tbl-Sample]"
            DoCmd.SetWarnings True

End Sub


หนูเองก็ไม่ทราบว่ามันเกี่ยงข้องกันอย่างไร อยากให้อาจารย์ช่วยอธิบายความหมายของคำสั่งนี้ด้วยค่ะ ว่ามันช่วยให้ลบข้อมูลเร็วขึ้นได้อย่างไร
2 @R05294
ผมก็ไม่เคยมีข้อมูลตัวอย่าง ปริมาณมากขนาดนั้นสักที เลยไม่ค่อยเห็นผลแตกต่าง
แต่เอาเป็นว่า ลองผิดลองถูกก็แล้วกันครับ
DoCmd.RunSQL "delete from [Tbl-Sample]"

+++เอาเครื่องหมาย ดอกจันทน์ ออกจากประโยค SQL ครับ ++
      ด้วยความเข้าใจส่วนตัว ว่า "การที่มี เครื่องหมาย ดอกจันทน์ กับไม่มีเครื่องหมาย มันแตกต่างกันดังนี้"

สมมติว่ามีปู อยู่ในถังครึ่งถัง (ไปจับมันมาใส่ไว้ หลายตัว)
             Delete * From       มันจะจับปูมาทีละตัวแล้วหักทิ้งทีละขาก่อน สุดท้ายค่อยโยนตัวปูทิ้ง เพราะ * มันหมายถึง ทุกๆ ฟิลด์ ดังนั้นมันจึงมีการสำรวจ ทุกๆ ฟิลด์ของทุกๆ เรคคอร์ด
              แต่ถ้าใช้ Delete From (ไม่มี *)
มันจะใช้วิธี เทถังทิ้งทันทีครับ มันจะไม่ไปไล่จับปูทีละตัว

อิอิ ขอย้ำว่าเป็นความเชื่อส่วนบุคคลครับ อิอิ


และรอความเห็นและความรู้เพิ่มเติมจากท่านอื่นๆ ต่ออีกครับ
3 @R05297
ถ้าใช้ RUNSQL method กับ Action query (INSERT, UPDATE, DELETE) แล้วอยากให้เร็ว ก็ต้องระบุ FALSE ต่อท้าย เช่น DoCmd.RunSQL "delete * from [Tbl-Sample]", FALSE เพราะพารามิเตอร์ตัวหลังนี้ ถ้าเป็น TRUE หรือละไว้ ก็จะหมายถึงให้ใช้ Transaction เป็นตัวควบคุมการปรับปรุงเรคอร์ดด้วย หมายถึงว่า ทำทำได้ก็จะทำได้ทั้งหมด หรือถ้าระหว่างทำเกิดปัญหาขึ้นก็จะทำการ Rollback Transaction ให้ทั้งหมด แต่เมื่อระบุเป็น FALSE ก็จะไม่มีการใช้ Transaction ดังนั้นถ้าระหว่างทำเกิดปัญหาใดไป เรคอร์ดที่ได้ทำไปแล้วก็จะถูกกระทำไปไม่สามารถยกเลิกได้

เพราะมันมีการใช้ Transaction Control นี่เอง จึงทำให้ช้าอย่างเห็นได้ชัดเมื่อกระทำกับเรคอร์ดจำนวนมากๆ
4 @R05299
ขอเรียนถามเพิ่มเติมค่ะอาจารย์

อยากให้เร็ว ก็ต้องระบุ FALSE ต่อท้าย

หมายความว่าให้ระบุ False ต่อท้ายในทุกบรรทัดที่ใช้ DoCmd.RunSQL เลยหรือเปล่าคะ หรือระบุแค่บรรทัดแรกเท่านั้น

ขอบคุณค่ะ
5 @R05303
ระบุบรรทัดไหน ก็มีผลเฉพาะบรรทัดนั้นครับ
6 @R05305
ขอบคุณค่ะอาจารย์

หนูลองทำตามแล้ว เห็นผลว่าเร็วขึ้นชัดเจนเลยค่ะ
-) ตอนแรก ดื่มกาแฟหมดแก้วแล้ว ยังลบไม่เสร็จ
-) ตอนนี้ เพียงเริ่มชงกาแฟ ก็ลบเสร็จแล้วค่ะ

7 @R05306
ผมลองตรวจสมมุติฐานของ อ.yeadram ดู จากการใช้ ShowPlan option ของ Jet Engine (ดูใน http://msdn.microsoft.com/en-us/library/aa188211%28office.10%29.aspx หัวข้อ ShowPlan option) ไม่ปรากฏว่าจะมีการทำอะไรที่แตกต่างกันระหว่างการใช้ * หรือไม่ใช้ในคำสั่ง DELETE นะครับ
8 @R05307
โอ้ว ยาวเฟื้อยเลยครับ อาจารย์
อังกฤษล้วนๆ เห็นแล้วท้อ ขอบคุณครับอาจารย์ที่จัดหามาให้ แสดงว่าความเชื่อของผมไม่น่าจะถูกซินะครับ อิอิ
9 @R05309
เพิ่งรู้นะครับนี่ว่าใช้
For next เร็วกว่า Do loop
ใช้ Len(ตัวแปร) = 0 เร็วกว่า if (ตัวแปร) = "" และอีกมากมาย
ลองดูคำแนะนำพร้อมกับ % ที่เร็วกว่าตามตารางที่ผม copy มาให้ดูกันเล่นๆสิครับ
Table 15.4. Summary of the Results of the VBA Performance Tests
Test      Optimization      Ratio of Elapsed Times (Smaller Is Better)
1      Use timeGetTime() rather than Timer      25%
2      Cache object references      40%
4      Use vbNullString instead of "" to initialize      35%
5      Be careful with string concatenation      15%
6      Use Mid$ statement rather than concatenation      55%
7      Use isCharAlphaNumeric() instead of ASCII values      55%
8      Use StrComp to compare short strings      45%
9      Use Like with wildcards      35%
10      Use "$" string functions when possible      60%
11      Use Integers instead of variants      50%
Test      Optimization      Ratio of Elapsed Times (Smaller Is Better)
12      Use Integer division (\) whenever possible      70%
13      Use logical assignments when possible      65%
14      Use Not to toggle between True and False      45%
15      Don't use Byte variables for speed      80%
16      Use For . . . Next rather than Do . . . Loop      50%
17      Be careful with IIf()      50%
18      Use If . . . Then rather than IIf      30%
19      Don't call DoEvents each time you loop      10%
20      Put the most likely candidate first in Select Case      15%
21      In arrays, For . . . Next faster than For Each . . . Next      75%
22      In collections, For Each . . . Next faster than For . . . Next      2%
23      Set a collection to New collection to clear it      10%
24      Use early binding      10%
10 @R05315
แนะนำเพิ่มเติมว่า ถ้าเปลี่ยนจาก DoCmd.RunSQL มาเป็น CurrentDB.Execute "คำสั่ง SQL", dbFailOnError จะทำให้ทำงานได้เร็วกว่า แต่จะเร็วกว่ามากน้อยแค่ไหน ต้องทดลองดูครับ และการใช้ .Execute ก็ไม่ต้องกำหนด DoCmd.SetWarnings False/True เพราะมันจะไม่มีคำเตือนเหล่านี้ขึ้นมา เหตุเพราะว่า .RunSQL เป็น method ของ Access   ข้อดีคือมันสามารถแปลความหมายของการอ้างอิง Access Object ได้ด้วย เช่น

"DELETE * FROM table WHERE Field = Forms!FormName!TextBoxName"

จากนั้นจึงค่อยส่งต่อไปยัง DAO ให้จัดการข้อมูลต่อไป ดังนั้นจึงมีกระบวนการทำงานในหลายขั้นตอนกว่าการสั่ง .Execute ซึ่งเป็น method ของอ๊อปเจ็คใน DAO โดยตรง แต่ก็แน่นอนว่า .Execute จะไม่สามารถตีความหมายการอ้างอิง Access Object ได้เหมือนอย่าง .RunSQL เราต้องตีความหมายนั้นก่อน แล้วค่อยนำมาประกอบเป็น SQL Command เช่น

"DELETE * FROM table WHERE Field = " & Forms!FormName!TextBoxName
11 @R05319
ทดลองเปลี่ยนดูแล้วค่ะอาจารย์

แต่ไม่รู้สึกถึงความแตกต่างที่ชัดเจนมากนัก
จะรอนำไปทดลองกับข้อมูลที่มากกว่านี้ดู ซึ่งอาจเห็นผลที่ชัดเจนขึ้นนะคะ

ขอบคุณค่ะ
12 @R05430
พอดีค้น Google เข้ามาเจอปัญหาเดียวกับที่ผมเจออยู่ ตอนนี้เลยพบทางออกแล้ว
แต่ กรณีย์ของผม สังเกตุดูว่า ถ้าเปิดเครื่องครั้งแรกแล้วสั่งลบข้อมูล มันจะใช้เวลามาก แต่หากทดลองลบครั้งที่สองนี่จะใช้เวลาเพียงนิดเดียว เหมือนกับว่า CPU มันจำคำสั่งลบครั้งที่แล้วเอาไว้ ทำให้ลบครั้งที่ 2,3,4...จะเร็วกว่าครั้งแรกอย่างมาก
รู้สึกจะเคยค้นเจอว่า มีคำสั่งที่สามารถ สั่งให้ CPU หยุดทำงานส่วนอื่นๆไว้ก่อน แล้วมาทำงานตามคำสั่งนี้เพียงอย่างเดียว
จึงขออนุญาตเรียนถามว่า แนวคิดนี้เป็นจริงหรือไม่ หากเป็นจริงได้ อยากขอทราบคำสั่งนี้ตลอดจนวิธีใช้ด้วยครับ
13 @R05431
มีคำสั่ง DoEvents ซึ่งปล่อยให้ CPU ไปทำงานอื่นๆก่อน เมื่อถึงเวลาตามที่ OS กำหนด ก็จะกลับมาทำงานบรรทัดต่อไปของ VBA

ถ้าจะถามว่ามีคำสั่งให้หยุดงานอื่นๆไหม ? ตอบว่าโดยคำสั่งของ VBA เองไม่มีครับ แต่คำสั่งในระดับ OS ที่เราเรียกผ่าน Windows API น่าจะมี และน่าจะมีหลายๆวิธี แต่ผมมั่นใจว่าไม่ใช่แนวคิดที่ถูกต้องแน่นอน

ที่มันทำงานได้เร็วในครั้งที่สองและครั้งต่อๆไป มันเนื่องจากหลายๆเหตุผล แต่ส่วนใหญ่ก็เป็นเรื่องของ การที่มันจำ "อะไรหลายๆอย่าง" เอาไว้ ซึ่งทำให้มันลดเวลาการทำงานลงได้ ซึ่งมีตั้งแต่ระดับ Access เอง   ระดับ OS   ระดับ Hardware   และอาจรวมไปถึงอุปกรณ์ทางด้าน Network และ Server ด้วย
@ ประกาศใช้งานเว็บบอร์ดใหม่ => บอร์ดเรียนรู้ Access สำหรับคนไทย
แล้วจะใส่ลิ้งอ้างอิงมาที่โพสต์เก่านี้หรือไม่ก็ตามสะดวกครับ
Time: 0.3507s