การเพิ่ม work_mem และ shared_buffers บน Postgres 9.2 ทำให้การสืบค้นช้าลงอย่างมาก


39

ฉันมีอินสแตนซ์ PostgreSQL 9.2 ที่ทำงานบน RHEL 6.3, เครื่อง 8-core พร้อม RAM ขนาด 16GB เซิร์ฟเวอร์ทุ่มเทให้กับฐานข้อมูลนี้ เนื่องจาก postgresql.conf เริ่มต้นค่อนข้างอนุรักษ์นิยมเกี่ยวกับการตั้งค่าหน่วยความจำฉันคิดว่าอาจเป็นความคิดที่ดีที่จะอนุญาตให้ Postgres ใช้หน่วยความจำเพิ่มเติม เพื่อประหลาดใจของฉันคำแนะนำต่อไปนี้ในwiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Serverชะลอตัวลงอย่างมากในทางปฏิบัติทุกแบบสอบถามที่ฉันเรียกใช้

ฉันยังลองใช้ pgtune ซึ่งให้คำแนะนำต่อไปนี้พร้อมปรับพารามิเตอร์เพิ่มเติม แต่นั่นก็ไม่ได้เปลี่ยนแปลงอะไรเลย มันแสดงให้เห็น shared_buffers ขนาด 1/4 ของ RAM ซึ่งดูเหมือนจะสอดคล้องกับคำแนะนำที่อื่น (และโดยเฉพาะกับ PG wiki โดยเฉพาะ)

default_statistics_target = 50
maintenance_work_mem = 960MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 11GB
work_mem = 96MB
wal_buffers = 8MB
checkpoint_segments = 16
shared_buffers = 3840MB
max_connections = 80

ฉันพยายามทำดัชนีฐานข้อมูลทั้งหมดใหม่หลังจากเปลี่ยนการตั้งค่า (โดยใช้reindex database) แต่ก็ไม่ได้ช่วยอะไร ฉันเล่นกับ shared_buffers และ work_mem การเปลี่ยนจากค่าเริ่มต้นที่อนุรักษ์นิยมอย่างค่อยเป็นค่อยไป (128k / 1MB) ค่อยๆลดลงประสิทธิภาพ

ฉันวิ่งไปซักEXPLAIN (ANALYZE,BUFFERS)สองสามข้อและผู้ร้ายดูเหมือนว่าการเข้าร่วมแฮชช้ากว่ามาก ทำไมฉันถึงไม่ชัดเจน

เพื่อให้ตัวอย่างเฉพาะฉันมีแบบสอบถามต่อไปนี้ มันทำงานใน ~ 2100ms ในการกำหนดค่าเริ่มต้นและ ~ 3300ms ในการกำหนดค่าด้วยขนาดบัฟเฟอร์ที่เพิ่มขึ้น:

select count(*) from contest c
left outer join contestparticipant cp on c.id=cp.contestId
left outer join teammember tm on tm.contestparticipantid=cp.id
left outer join staffmember sm on cp.id=sm.contestparticipantid
left outer join person p on p.id=cp.personid
left outer join personinfo pi on pi.id=cp.personinfoid
where pi.lastname like '%b%' or pi.firstname like '%a%';

EXPLAIN (ANALYZE,BUFFERS) สำหรับแบบสอบถามด้านบน:

คำถามคือทำไมฉันสังเกตการลดลงประสิทธิภาพเมื่อฉันเพิ่มขนาดบัฟเฟอร์? เครื่องไม่มีหน่วยความจำไม่เพียงพอ การจัดสรรหากหน่วยความจำที่แชร์ใน OS คือ ( shmmaxและshmall) ตั้งเป็นค่าที่มีขนาดใหญ่มากนั่นไม่น่าจะมีปัญหา ฉันไม่ได้รับข้อผิดพลาดในบันทึก Postgres เช่นกัน ฉันกำลังเรียกใช้ autovacuum ในการกำหนดค่าเริ่มต้น แต่ฉันไม่คิดว่ามันจะเกี่ยวข้องกับมัน การค้นหาทั้งหมดถูกเรียกใช้บนเครื่องเดียวกันห่างกันเพียงไม่กี่วินาทีเพียงแค่เปลี่ยนการกำหนดค่า (และเริ่มการทำงาน PG ใหม่)

แก้ไข: ฉันเพิ่งพบข้อเท็จจริงที่น่าสนใจเป็นพิเศษ: เมื่อฉันทำการทดสอบเดียวกันกับ iMac (OSX 10.7.5) กลางปี ​​2010 ของฉันด้วย Postgres 9.2.1 และ 16GB RAM ฉันไม่พบว่าการทำงานช้าลง โดยเฉพาะ:

set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms

เมื่อฉันทำแบบสอบถามเดียวกันทั้งหมด (อย่างใดอย่างหนึ่งด้านบน) ด้วยข้อมูลเดียวกันบนเซิร์ฟเวอร์ฉันได้รับ 2100 ms กับ work_mem = 1MB และ 3200 ms ด้วย 96 MB

Mac มี SSD ดังนั้นจึงเข้าใจได้เร็วขึ้น แต่ก็แสดงพฤติกรรมที่ฉันคาดหวัง

เห็นแล้วยังอภิปรายติดตาม pgsql


1
ดูเหมือนว่าในกรณีที่ช้าลงทุกขั้นตอนจะช้าลงอย่างสอดคล้อง การตั้งค่าอื่น ๆ ยังคงเหมือนเดิมหรือไม่?
dezso

1
มันอาจคุ้มค่าที่คุณจะถามคำถามนี้ในฟอรัมที่มีความเชี่ยวชาญมากกว่าที่จะเป็นแบบทั่วไป ในกรณีนี้ฉันขอแนะนำรายชื่อผู้รับจดหมาย pgsql ทั่วไปarchives.postgresql.org/pgsql-general
Colin 't Hart

1
โอ้และกลับมารายงานและโปรดตอบคำถามของคุณเองหากคุณพบคำตอบ! (สิ่งนี้ได้รับอนุญาตสนับสนุนแม้)
Colin 't Hart

1
ฉันสงสัยว่า Postgres คล้ายกันกับ Oracle ในเรื่องนี้: ฉันจำหลักสูตรของ Jonathan Lewis (Oracle guru) ซึ่งเขาแสดงให้เห็นว่าการจัดสรรหน่วยความจำให้มากขึ้นในบางครั้งทำให้ช้าลง ฉันลืมข้อมูลเฉพาะ แต่มันเป็นเรื่องเกี่ยวกับที่ Oracle ทำบางส่วนแล้วเขียนออกไปยังที่เก็บข้อมูลชั่วคราวแล้วรวมเข้าด้วยกันภายหลัง หน่วยความจำเพิ่มเติมทำให้กระบวนการนี้ช้าลง
โคลิน 't ฮาร์

2
คำถามนี้ถูกโพสต์ใน pgsql-performance: archives.postgresql.org/pgsql-performance/2012-11/msg00004.php
Petr Praus

คำตอบ:


28

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

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


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

work_mem : จำนวนหน่วยความจำที่เราสามารถจัดสรรสำหรับการเรียงลำดับหรือการดำเนินการเข้าร่วมที่เกี่ยวข้อง นี่คือการดำเนินการต่อไม่ต่องบหรือต่อ back-end ดังนั้นแบบสอบถามที่ซับซ้อนเดียวสามารถใช้หน่วยความจำจำนวนนี้หลายครั้ง ไม่ชัดเจนว่าคุณกำลังกดปุ่มขีด จำกัด นี้ แต่มันก็คุ้มค่าที่จะต้องทราบและตระหนักถึง ถ้าคุณเพิ่มมากเกินไปคุณจะสูญเสียหน่วยความจำที่อาจมีอยู่สำหรับแคชการอ่านและบัฟเฟอร์ที่แชร์

shared_buffers : จำนวนหน่วยความจำที่จะจัดสรรให้กับคิวเพจ PostgreSQL จริง ตอนนี้ชุดฐานข้อมูลที่น่าสนใจของคุณจะยังคงอยู่ในหน่วยความจำแคชที่นี่และในบัฟเฟอร์การอ่าน อย่างไรก็ตามสิ่งนี้จะทำให้แน่ใจได้ว่าข้อมูลที่ใช้บ่อยที่สุดในแบ็กเอนด์ทั้งหมดได้รับแคชและไม่ได้ล้างข้อมูลลงดิสก์ บน Linux แคชนี้ช้ากว่าดิสก์แคชระบบปฏิบัติการอย่างเห็นได้ชัด แต่ให้การรับประกันว่าแคชดิสก์ระบบปฏิบัติการไม่ได้ทำและโปร่งใสสำหรับ PostgreSQL นี่ค่อนข้างชัดเจนว่าปัญหาของคุณอยู่ที่ใด

ดังนั้นสิ่งที่จะเกิดขึ้นคือเมื่อเรามีคำขอเราจะตรวจสอบบัฟเฟอร์ที่ใช้ร่วมกันก่อนเนื่องจาก PostgreSQL มีความรู้อย่างลึกซึ้งเกี่ยวกับแคชนี้และค้นหาหน้าต่างๆ หากพวกเขาไม่ได้อยู่ที่นั่นเราขอให้ระบบปฏิบัติการเปิดจากไฟล์และหากระบบปฏิบัติการได้ผลก็จะส่งกลับสำเนาแคช (นี้เร็วกว่าบัฟเฟอร์ที่ใช้ร่วมกัน แต่ Pg ไม่สามารถบอกได้ว่ามันเป็นแคชหรือบน ดิสก์และดิสก์ช้าลงมากดังนั้น PostgreSQL โดยทั่วไปจะไม่ใช้โอกาสนั้น) โปรดทราบว่าการดำเนินการนี้มีผลต่อการเข้าถึงหน้าแบบสุ่มและต่อเนื่องเช่นกัน ดังนั้นคุณอาจได้ประสิทธิภาพที่ดีขึ้นด้วยการตั้งค่า shared_buffers ที่ต่ำลง

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


10

นอกเหนือจากผลกระทบที่ขัดแย้งที่ดูเหมือนว่าการเพิ่มwork_memประสิทธิภาพการลดลง ( @Chrisอาจมีคำอธิบาย) คุณสามารถปรับปรุงการทำงานของคุณได้อย่างน้อยสองวิธี

  • เขียนซ้ำสองปลอมLEFT JOINด้วย JOINนั่นอาจทำให้ผู้วางแผนคิวรี่สับสนและนำไปสู่แผนการที่ด้อยกว่า

SELECT count(*) AS ct
FROM   contest            c
JOIN   contestparticipant cp ON cp.contestId = c.id
JOIN   personinfo         pi ON pi.id = cp.personinfoid
LEFT   JOIN teammember    tm ON tm.contestparticipantid = cp.id
LEFT   JOIN staffmember   sm ON sm.contestparticipantid = cp.id
LEFT   JOIN person        p  ON p.id = cp.personid
WHERE (pi.firstname LIKE '%a%'
OR     pi.lastname  LIKE '%b%')
  • สมมติว่ารูปแบบการค้นหาที่แท้จริงของคุณเลือกได้มากกว่าให้ใช้ดัชนี trigram pi.firstnameและpi.lastnameเพื่อรองรับการLIKEค้นหาที่ไม่ได้ยึดไว้ (รูปแบบที่สั้นกว่า'%a%'ได้รับการสนับสนุนเช่นกัน แต่ดัชนีไม่น่าจะช่วยให้ภาคแสดงที่ไม่ได้เลือกได้):

CREATE INDEX personinfo_firstname_gin_idx ON personinfo USING gin (firstname gin_trgm_ops);
CREATE INDEX personinfo_lastname_gin_idx  ON personinfo USING gin (lastname gin_trgm_ops);

หรือดัชนีหลายรายการหนึ่งรายการ:

CREATE INDEX personinfo_name_gin_idx ON personinfo USING gin (firstname gin_trgm_ops, lastname gin_trgm_ops);

ควรทำให้ข้อความค้นหาของคุณเร็วขึ้นสักหน่อย คุณต้องติดตั้งโมดูลเพิ่มเติมpg_trgmสำหรับสิ่งนี้ รายละเอียดภายใต้คำถามที่เกี่ยวข้องเหล่านี้:


คุณลองตั้งค่าwork_mem ในเครื่องแล้วหรือยังสำหรับธุรกรรมปัจจุบันเท่านั้น ?

SET LOCAL work_mem = '96MB';

สิ่งนี้จะช่วยให้การทำธุรกรรมพร้อมกันจากการกิน RAM มากขึ้นอาจจะอดอยากซึ่งกันและกัน


3
ฉันต้องการข้อเสนอแนะ work_mem ในพื้นที่ของ Erwin ที่สอง เนื่องจาก work_mem เปลี่ยนประเภทของแบบสอบถามที่เร็วกว่าคุณอาจต้องเปลี่ยนมันสำหรับบางแบบสอบถาม ระดับ work_mem ต่ำเช่นที่ดีที่สุดสำหรับการค้นหาที่เรียงลำดับ / เข้าร่วมจำนวนน้อยของบันทึกในรูปแบบที่ซับซ้อน (เช่นจำนวนมากเข้าร่วม) ในขณะที่ระดับ work_mem สูงจะดีที่สุดสำหรับการค้นหาที่มีการเรียงลำดับไม่กี่ แต่ที่เรียงลำดับหรือเข้าร่วมจำนวนมากในครั้งเดียว .
Chris Travers

ฉันปรับปรุงการค้นหาในระหว่างนี้ (คำถามคือตั้งแต่เดือนตุลาคมปีที่แล้ว) แต่ขอบคุณ :) คำถามนี้เกี่ยวกับผลที่ไม่คาดคิดมากกว่าการสืบค้นเฉพาะ แบบสอบถามทำหน้าที่เป็นหลักในการแสดงให้เห็นถึงผลกระทบ ขอบคุณสำหรับเคล็ดลับในดัชนีฉันจะลองดู!
Petr Praus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.