ปรับ PostgreSQL ให้เหมาะสมเพื่อการทดสอบที่รวดเร็ว


203

ฉันเปลี่ยนมาใช้ PostgreSQL จาก SQLite สำหรับแอปพลิเคชั่น Rails ทั่วไป

ปัญหาคือรายละเอียดการรันช้าลงเมื่อใช้ PG
บน SQLite จะเอา ~ 34 วินาทีบน PG มัน ~ 76 วินาทีซึ่งเป็นมากกว่า 2x ช้าลง

ดังนั้นตอนนี้ฉันต้องการใช้เทคนิคบางอย่างเพื่อทำให้ประสิทธิภาพของ specs เทียบกับ SQLiteโดยไม่มีการแก้ไขโค้ด (โดยเฉพาะการตั้งค่าตัวเลือกการเชื่อมต่อซึ่งอาจเป็นไปไม่ได้)

สิ่งที่ชัดเจนจากหัวของฉันคือ:

  • RAM Disk (การตั้งค่าที่ดีกับ RSpec บน OSX จะดีสำหรับการดู)
  • ตารางที่ไม่ถูกบล็อก (สามารถนำไปใช้กับฐานข้อมูลทั้งหมดได้หรือไม่ดังนั้นฉันจึงไม่ได้เปลี่ยนสคริปต์ทั้งหมด)

อย่างที่คุณอาจจะเข้าใจว่าฉันไม่สนใจเกี่ยวกับความน่าเชื่อถือและส่วนที่เหลือ (DB เป็นเพียงการทิ้งสิ่งที่นี่)
ฉันต้องการที่จะได้รับส่วนใหญ่ของ PG และทำให้มันเป็นไปอย่างรวดเร็วในขณะที่มันอาจจะสามารถ

คำตอบที่ดีที่สุดจะอธิบายถึงเทคนิคในการทำเช่นนั้นการตั้งค่าและข้อเสียของเทคนิคเหล่านั้น

อัปเดต: fsync = off + full_page_writes = offลดเวลาเพียง ~ 65 วินาที (~ -16 วินาที) เริ่มต้นดี แต่ไกลจากเป้าหมาย 34

อัปเดต 2:ฉันพยายามใช้ RAM ดิสก์แต่ประสิทธิภาพเพิ่มขึ้นอยู่ในระยะขอบผิดพลาด ดังนั้นดูเหมือนจะไม่คุ้มค่า

อัปเดต 3: * ฉันพบคอขวดที่ใหญ่ที่สุดและตอนนี้สเป็คของฉันทำงานได้เร็วเท่ากับ SQLite

ประเด็นสำคัญคือการทำความสะอาดฐานข้อมูลที่ไม่ตัด เห็นได้ชัดว่า SQLite เร็วเกินไป

หากต้องการ "แก้ไข" ฉันจะเปิดธุรกรรมก่อนการทดสอบแต่ละครั้งและย้อนกลับในตอนท้าย

ตัวเลขบางส่วนสำหรับการทดสอบประมาณ 700 ครั้ง

  • การตัด: SQLite - 34s, PG - 76s
  • ธุรกรรม: SQLite - 17s, PG - 18s

เพิ่มความเร็ว 2x สำหรับ SQLite เพิ่มความเร็ว 4x สำหรับ PG


2
ฉันสงสัยจริงๆว่าคุณจะไปให้เร็วที่สุดเท่าที่ SQLite SQLite กับผู้ใช้คนเดียวคือเมามันรวดเร็ว การออกแบบของ SQLite นั้นรวดเร็วมากโดยมีจำนวนผู้ใช้น้อยและมีขนาดไม่ดี การออกแบบของ Pg นั้นมีขนาดที่ดี แต่ไม่เร็วสำหรับการทำงานแบบกลุ่มจำนวนมากด้วยผู้ใช้เพียงคนเดียว
Craig Ringer

1
ฉันรู้ว่า แต่มีบางกรณีที่ฉันหวังว่าจะเพิ่มประสิทธิภาพ PG สำหรับ (ทดสอบการทำงาน) ดังนั้นจึงเร็วที่สุดเท่าที่จะเป็นไปได้ ฉันไม่รังเกียจที่จะช้าลงเล็กน้อยแต่ 2.2x ช้าเกินไป ดูว่าฉันหมายถึงอะไร
Dmytrii Nagirniak

+1 ฉันสนใจมากในการอัปเดตเกี่ยวกับวิธีใช้ดิสก์ RAM ถ้าคุณได้ผลลัพธ์ที่เกี่ยวข้อง
tscho

@tscho ฉันจะโพสต์ที่นี่แน่นอน แต่ต้องใช้เวลาสักพักเพราะฉันกำลังทำงานกับสิ่งอื่น ๆ และ "ค้นคว้า" เนื้อหา PG ใน "พื้นหลัง"
Dmytrii Nagirniak

มีการใส่ข้อมูลปัญหาของคุณได้หรือสอบถาม ? คำถามของคุณยังไม่ชัดเจน
a_horse_with_no_name

คำตอบ:


281

ก่อนอื่นให้ใช้ PostgreSQL เวอร์ชันล่าสุดเสมอ การปรับปรุงประสิทธิภาพมักจะมาถึงดังนั้นคุณอาจเสียเวลาหากคุณกำลังปรับรุ่นเก่า ตัวอย่างเช่นPostgreSQL 9.2 ช่วยปรับปรุงความเร็วTRUNCATEและแน่นอนเพิ่มสแกนเฉพาะดัชนี แม้แต่การปล่อยเล็กน้อยควรทำตามเสมอ ดูนโยบายรุ่น

Don'ts

อย่าไม่ใส่ตารางบน ramdisk หรือจัดเก็บไม่คงทนอื่น

หากคุณสูญเสียพื้นที่ตารางฐานข้อมูลทั้งหมดอาจเสียหายและยากต่อการใช้งานโดยไม่ต้องทำงานที่สำคัญ มีประโยชน์น้อยมากเมื่อเทียบกับการใช้UNLOGGEDตารางและมี RAM จำนวนมากสำหรับแคชอยู่แล้ว

หากคุณต้องการระบบที่ใช้ ramdisk initdbคลัสเตอร์ใหม่ทั้งหมดใน ramdisk โดยinitdbใช้อินสแตนซ์ PostgreSQL ใหม่บน ramdisk ดังนั้นคุณจึงมีอินสแตนซ์ PostgreSQL ที่ใช้แล้วทิ้งทั้งหมด

การกำหนดค่าเซิร์ฟเวอร์ PostgreSQL

เมื่อทำการทดสอบคุณสามารถกำหนดค่าเซิร์ฟเวอร์ของคุณสำหรับการดำเนินงานไม่คงทน แต่ได้เร็วขึ้น

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

คุณไม่ควรเปิดใช้งานfsync=offในการผลิตเว้นแต่คุณจะใช้ Pg เป็นฐานข้อมูลชั่วคราวสำหรับข้อมูลที่คุณสามารถสร้างขึ้นใหม่ได้จากที่อื่น หากว่าหากคุณกำลังจะปิด fsync ก็สามารถfull_page_writesปิดได้เช่นกัน ระวังfsync=offและfull_page_writesนำไปใช้ที่ระดับคลัสเตอร์ดังนั้นมันจะมีผลกับฐานข้อมูลทั้งหมดในอินสแตนซ์ PostgreSQL ของคุณ

สำหรับการใช้งานจริงคุณสามารถใช้synchronous_commit=offและตั้งค่า a commit_delayเนื่องจากคุณจะได้รับประโยชน์มากมายเช่นเดียวกับที่fsync=offไม่มีความเสี่ยงจากการทุจริตของข้อมูล คุณมีหน้าต่างเล็ก ๆ ของการสูญเสียข้อมูลล่าสุดถ้าคุณเปิดใช้งานการมอบหมาย async - แต่นั่นคือมัน

หากคุณมีตัวเลือกในการเปลี่ยนแปลง DDL เล็กน้อยคุณสามารถใช้UNLOGGEDตารางใน Pg 9.1+ เพื่อหลีกเลี่ยงการบันทึก WAL อย่างสมบูรณ์และได้รับการเพิ่มความเร็วที่แท้จริงด้วยค่าใช้จ่ายของตารางที่ถูกลบหากเซิร์ฟเวอร์ล่ม ไม่มีตัวเลือกการกำหนดค่าเพื่อให้ตารางทั้งหมดถูกเปิดใช้งานจะต้องถูกตั้งค่าในระหว่างCREATE TABLEนั้น นอกจากจะเป็นการดีสำหรับการทดสอบแล้วยังมีประโยชน์ถ้าคุณมีตารางที่เต็มไปด้วยข้อมูลที่สร้างขึ้นหรือไม่สำคัญในฐานข้อมูลที่มีสิ่งอื่นที่คุณต้องปลอดภัย

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

ปรับแต่งshared_buffersให้เหมาะกับภาระงานของคุณ สิ่งนี้ขึ้นอยู่กับระบบปฏิบัติการขึ้นอยู่กับว่าเกิดอะไรขึ้นกับเครื่องของคุณและต้องการการทดลองและข้อผิดพลาด ค่าเริ่มต้นเป็นแบบอนุรักษ์นิยมอย่างยิ่ง คุณอาจต้องเพิ่มขีด จำกัด หน่วยความจำที่แชร์สูงสุดของระบบปฏิบัติการหากคุณเพิ่มshared_buffersใน PostgreSQL 9.2 และต่ำกว่า; 9.3 และสูงกว่าเปลี่ยนวิธีที่พวกเขาใช้หน่วยความจำที่ใช้ร่วมกันเพื่อหลีกเลี่ยงปัญหานั้น

หากคุณใช้การเชื่อมต่อเพียงไม่กี่อย่างที่ทำงานมากมายwork_memให้เพิ่ม RAM เพื่อให้พวกเขาเล่นได้หลายประเภท ฯลฯ ระวังว่าการwork_memตั้งค่าที่สูงเกินไปอาจทำให้เกิดปัญหาหน่วยความจำไม่เพียงพอเพราะมันไม่ได้เรียงต่อกัน ต่อการเชื่อมต่อดังนั้นหนึ่งแบบสอบถามสามารถมีหลายประเภทซ้อนกัน คุณจริงๆต้องมีการเพิ่มwork_memถ้าคุณสามารถดูประเภททะลักไปยังดิสก์ในEXPLAINหรือเข้าสู่ระบบด้วยlog_temp_filesการตั้งค่า (แนะนำ) แต่ค่าที่สูงขึ้นนอกจากนี้ยังอาจช่วยให้หน้าเลือกแผนอย่างชาญฉลาด

ตามที่กล่าวไว้โดยผู้โพสต์คนอื่นที่นี่ก็ควรที่จะวาง xlog และตารางหลัก / ดัชนีใน HDD แยกต่างหากถ้าเป็นไปได้ พาร์ติชันแยกต่างหากนั้นไม่มีจุดหมายเลยคุณต้องการไดรฟ์แยกต่างหาก การแยกนี้มีประโยชน์น้อยกว่ามากหากคุณใช้งานfsync=offและแทบไม่มีเลยหากคุณกำลังใช้UNLOGGEDตาราง

สุดท้ายปรับคำค้นหาของคุณ ตรวจสอบให้แน่ใจว่าของคุณrandom_page_costและseq_page_costสะท้อนให้เห็นถึงประสิทธิภาพของระบบของคุณให้แน่ใจว่าeffective_cache_sizeถูกต้อง ฯลฯ ใช้EXPLAIN (BUFFERS, ANALYZE)เพื่อตรวจสอบแผนแบบสอบถามแต่ละรายการและเปิดauto_explainโมดูลเพื่อรายงานแบบสอบถามที่ช้าทั้งหมด คุณสามารถปรับปรุงประสิทธิภาพการสืบค้นได้อย่างมากเพียงแค่สร้างดัชนีที่เหมาะสมหรือปรับแต่งพารามิเตอร์ค่าใช้จ่าย

AFAIK UNLOGGEDมีวิธีการตั้งค่าฐานข้อมูลทั้งหมดหรือคลัสเตอร์ที่ไม่มี มันน่าสนใจที่จะสามารถทำได้ พิจารณาถามเกี่ยวกับรายการส่งจดหมายของ PostgreSQL

ปรับแต่งโฮสต์ OS

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

ใน Linux คุณสามารถควบคุมได้กับระบบย่อยหน่วยความจำเสมือนของการตั้งค่าเช่นdirty_*dirty_writeback_centisecs

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

การปรับแต่งนี้ต้องใช้การตั้งค่าเพื่อดูว่าอะไรทำงานได้ดีที่สุดสำหรับภาระงานของคุณ

บนเมล็ดใหม่คุณอาจต้องการเพื่อให้แน่ใจว่าvm.zone_reclaim_modeมีการตั้งค่าให้เป็นศูนย์ที่จะสามารถก่อให้เกิดปัญหาที่รุนแรงประสิทธิภาพการทำงานกับระบบ NUMA (ระบบมากที่สุดวันนี้) shared_buffersเนื่องจากการปฏิสัมพันธ์กับวิธีการจัดการ

เคียวรีและการปรับเวิร์กโหลด

นี่คือสิ่งที่ต้องมีการเปลี่ยนแปลงรหัส; พวกเขาอาจไม่เหมาะกับคุณ บางอย่างเป็นสิ่งที่คุณอาจนำไปใช้

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

หากเป็นไปได้ให้ใช้ตารางชั่วคราว พวกเขาไม่ได้สร้างปริมาณการใช้งาน WAL ดังนั้นพวกเขาจึงเร็วขึ้นสำหรับการแทรกและการปรับปรุง บางครั้งมันก็คุ้มค่าที่จะรวมกลุ่มข้อมูลลงในตารางชั่วคราวจัดการมันตามที่คุณต้องการจากนั้นทำการINSERT INTO ... SELECT ...คัดลอกไปยังตารางสุดท้าย โปรดทราบว่าตารางชั่วคราวต่อเซสชัน หากเซสชั่นของคุณสิ้นสุดลงหรือการเชื่อมต่อของคุณขาดหายไปตาราง temp จะหายไปและไม่มีการเชื่อมต่ออื่นใดที่สามารถดูเนื้อหาของตาราง temp ของเซสชัน

หากคุณใช้ PostgreSQL 9.1 หรือใหม่กว่าคุณสามารถใช้UNLOGGEDตารางสำหรับข้อมูลที่คุณสามารถเสียได้เช่นสถานะเซสชัน สิ่งเหล่านี้สามารถมองเห็นได้ในเซสชันต่างๆและเก็บรักษาไว้ระหว่างการเชื่อมต่อ พวกเขาจะถูกตัดถ้าเซิร์ฟเวอร์ปิดอย่างไม่สะอาดดังนั้นจึงไม่สามารถใช้กับสิ่งที่คุณไม่สามารถสร้างใหม่ได้ แต่มันยอดเยี่ยมสำหรับแคชมุมมองรูปธรรมตารางสถานะ ฯลฯ

DELETE FROM blah;โดยทั่วไปทำไม่ได้ ใช้TRUNCATE TABLE blah;แทน มันเร็วกว่ามากเมื่อคุณทิ้งแถวทั้งหมดในตาราง ตัดทอนตารางจำนวนมากในการTRUNCATEโทรหนึ่งครั้งหากทำได้ มีข้อแม้ถ้าคุณกำลังทำTRUNCATESโต๊ะเล็ก ๆ หลาย ๆ ครั้งซ้ำแล้วซ้ำอีกแม้ว่า; ดู: Postgresql ความเร็วการตัด

หากคุณไม่มีดัชนีของคีย์ต่างประเทศDELETEs ที่เกี่ยวข้องกับคีย์หลักที่อ้างอิงโดยคีย์ต่างประเทศเหล่านั้นจะช้าลงอย่างน่ากลัว ตรวจสอบให้แน่ใจว่าได้สร้างดัชนีดังกล่าวหากคุณคาดหวังDELETEจากตารางที่อ้างอิง TRUNCATEดัชนีไม่จำเป็นสำหรับ

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

ฮาร์ดแวร์

การมี RAM เพียงพอที่จะเก็บฐานข้อมูลทั้งหมดถือเป็นชัยชนะครั้งใหญ่หากคุณสามารถจัดการได้

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

การเรียนรู้

หนังสือ Greg Smith ของPostgreSQL 9.0 ประสิทธิภาพสูงยังคงมีความเกี่ยวข้องแม้จะอ้างถึงรุ่นที่ค่อนข้างเก่ากว่า ควรเป็นข้อมูลอ้างอิงที่มีประโยชน์

เข้าร่วมรายการส่งจดหมายทั่วไปของ PostgreSQL แล้วทำตาม

อ่าน:


10
ฉันยังสามารถแนะนำ PostgreSQL 9.0 High Performance โดย @GregSmith มันเป็นการอ่านที่ยอดเยี่ยมจริงๆ หนังสือเล่มนี้ครอบคลุมทุกแง่มุมของการปรับแต่งประสิทธิภาพจากเลย์เอาต์ดิสก์ไปจนถึงการปรับแต่งเคียวรีและให้ความเข้าใจที่ดีเกี่ยวกับ PG internals
tscho

10
ฉันไม่ได้เผยแพร่การอัปเดตสำหรับหนังสือ PostgreSQL 9.1 ซึ่งเป็นรุ่นเดียวตั้งแต่ตีพิมพ์เนื่องจากไม่มีการเปลี่ยนแปลงที่เกี่ยวข้องกับประสิทธิภาพเพียงพอใน 9.1 เพื่อรับประกัน
Greg Smith

3
เขียนดีมาก เช่นเดียวกับการอัปเดตเล็ก ๆ “ คุณอาจต้องเพิ่มขีด จำกัด หน่วยความจำที่แบ่งใช้สูงสุดของระบบปฏิบัติการหากคุณเพิ่ม shared_buffers” ไม่เป็นความจริงอีกต่อไป (สำหรับผู้ใช้ส่วนใหญ่) ภายใต้ PostgreSQL 9.3: postgresql.org/docs/9.3/static/release-9- 3.html # AEN114343
Gunnlaugur Briem

1
@brauliobo การทดสอบของฉันมักทำ tx จำนวนมากที่ TPS สูง ... เพราะฉันพยายามจำลองการผลิตรวมถึงปริมาณงานที่หนักมากพร้อมกัน หากคุณหมายถึง "การเชื่อมต่อเดี่ยวการทดสอบเชิงเส้น" ดังนั้นฉันจะเห็นด้วยกับคุณ
Craig Ringer

1
stackoverflow.com/questions/11419536/.. DELETE อาจเร็วกว่า TRUNCATE สำหรับตารางที่มีแถวไม่กี่แถวซึ่งน่าจะเป็นกรณีในการทดสอบ
Jonathan Crosmer

9

ใช้เค้าโครงดิสก์ที่แตกต่างกัน:

  • ดิสก์ที่แตกต่างกันสำหรับ $ PGDATA
  • ดิสก์อื่นสำหรับ $ PGDATA / pg_xlog
  • ดิสก์ที่แตกต่างกันสำหรับไฟล์ tem (ต่อฐานข้อมูล $ PGDATA / base // pgsql_tmp) (ดูหมายเหตุเกี่ยวกับ work_mem)

postgresql.conf tweaks:

  • shared_memory: 30% ของ RAM ที่ใช้ได้ แต่ไม่เกิน 6 ถึง 8GB ดูเหมือนว่าจะดีกว่าถ้ามีหน่วยความจำน้อยกว่า (2GB - 4GB) สำหรับการเขียนปริมาณงานที่มาก
  • work_mem: ส่วนใหญ่ใช้สำหรับแบบสอบถามแบบใช้เลือกข้อมูลที่มีประเภท / การรวมตัว นี่คือการตั้งค่าการเชื่อมต่อและแบบสอบถามสามารถจัดสรรค่านั้นหลายครั้ง หากข้อมูลไม่พอดีจะมีการใช้ดิสก์ (pgsql_tmp) ทำเครื่องหมายที่ "อธิบายการวิเคราะห์" เพื่อดูจำนวนหน่วยความจำที่คุณต้องการ
  • fsync และ synchronous_commit: ค่าเริ่มต้นปลอดภัย แต่ถ้าคุณสามารถทนต่อข้อมูลที่หายไปคุณสามารถปิดได้
  • random_page_cost: หากคุณมี SSD หรืออาเรย์ RAID ที่รวดเร็วคุณสามารถลดขนาดนี้เป็น 2.0 (RAID) หรือต่ำกว่า (1.1) สำหรับ SSD
  • checkpoint_segments: คุณสามารถเพิ่มได้ 32 หรือ 64 และเปลี่ยน checkpoint_completion_target เป็น 0.9 ค่าที่ต่ำกว่าช่วยให้กู้คืนข้อมูลได้เร็วขึ้นหลังการชน

4
โปรดทราบว่าหากคุณกำลังใช้งานอยู่fsync=offการวาง pg_xlog ในดิสก์แยกต่างหากจะไม่ดีขึ้นอีกต่อไป
intgr

ค่า 1.1 สำหรับ SSD ดูเหมือนไม่มีเงื่อนไขมาก ฉันรับรู้ว่ามันเป็นสิ่งที่ผู้เชี่ยวชาญบางคนแนะนำอย่างสุ่มสี่สุ่มห้า แม้แต่ SSD ยังเร็วกว่าสำหรับการอ่านตามลำดับมากกว่าการอ่านแบบสุ่ม
คิวเมนตัส

@ABB ใช่ แต่คุณได้รับเอฟเฟกต์แคชบัฟเฟอร์ OS ในที่ทำงานด้วย params ทุกคนเป็นบิตมือ wavey แล้ว ...
เครก Ringer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.