การเพิ่มคอลัมน์แบบ nullable ลงในตารางมีค่าใช้จ่ายมากกว่า 10 นาที


11

ฉันมีปัญหาในการเพิ่มคอลัมน์ใหม่ในตาราง
ฉันพยายามเรียกใช้สองสามครั้ง แต่หลังจากผ่านไปนานกว่า 10 นาทีฉันตัดสินใจยกเลิกคิวรีเนื่องจากเวลาล็อค

ALTER TABLE mytable ADD mycolumn VARCHAR(50);

ข้อมูลที่เป็นประโยชน์:

  • รุ่น PostgreSQL: 9.1
  • จำนวนแถว: ~ 250K
  • จำนวนคอลัมน์: 38
  • จำนวนคอลัมน์ที่ nullable: 32
  • จำนวนข้อ จำกัด : 5 (1 PK, 3 FK, 1 UNIQUE)
  • จำนวนดัชนี: 1
  • ประเภทระบบปฏิบัติการ: Debian Squeeze 64

ฉันพบข้อมูลที่น่าสนใจเกี่ยวกับวิธีที่ PostgreSQL จัดการคอลัมน์ที่ไม่มีค่า (ผ่าน HeapTupleHeader)

การเดาครั้งแรกของฉันคือเนื่องจากตารางนี้มีคอลัมน์ที่สามารถ nullable ได้ 32 คอลัมน์ซึ่งมี 8 บิตMAXALIGNHeapTupleHeader มีความยาว 4 ไบต์ (ยังไม่ผ่านการตรวจสอบและฉันไม่รู้วิธีการ)

ดังนั้นการเพิ่มคอลัมน์ nullable ใหม่อาจจำเป็นต้องมีการปรับปรุง HeapTupleHeader ในทุกแถวเพื่อเพิ่ม 8 บิตMAXALIGNใหม่ซึ่งอาจทำให้เกิดปัญหาประสิทธิภาพการทำงาน

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

ALTER TABLE mytable ALTER myothercolumn SET NOT NULL;

น่าเสียดายที่การเปลี่ยนแปลงนี้ใช้เวลานานกว่า 5 นาทีดังนั้นฉันจึงยกเลิก

คุณมีความคิดเกี่ยวกับสิ่งที่อาจทำให้ประสิทธิภาพการทำงานนี้เสียค่าใช้จ่ายหรือไม่?


1
ฉันสามารถบอกคุณได้ส่วนหนึ่งของมัน: การเปลี่ยนประเภทคอลัมน์เป็นประเภทอื่นที่ไม่เข้ากันได้กับไบนารีจะสร้างคอลัมน์ใหม่คัดลอกข้อมูลและตั้งค่าคอลัมน์เก่าเป็นแบบหล่น อย่างไรก็ตามSET NOT NULLไม่ได้เปลี่ยนประเภทเพียงเพิ่มข้อ จำกัด แต่ต้องตรวจสอบข้อ จำกัดกับตารางและต้องใช้การสแกนแบบเต็มตาราง 9.4 ปรับปรุงบางกรณีโดยการล็อคที่อ่อนแอ แต่ก็ยังมีน้ำหนักมาก
Craig Ringer

1
ก่อนที่จะสงสัยว่ามันทำงานได้ช้าคุณต้องตรวจสอบให้แน่ใจว่า ALTER TABLE ไม่ใช่แค่รอการล็อค พูดถึงมันในคำถามถ้าคุณได้ตรวจสอบ
Daniel Vérité

ขอบคุณ Craig และ Daniel เมื่อฉันรันคำสั่ง alter คำสั่งนั้นจะปรากฏเป็น pg_stat_activity โดยรอคำว่า "true" ฉันคิดว่านั่นหมายความว่าจะรอการล็อค! มันเป็นวิธีที่ดีสำหรับการตรวจสอบ? โดยวิธีก่อนที่จะใช้การเปลี่ยนแปลงนี้ทุกอย่างไปได้ดี แต่ไม่กี่วินาทีหลังจากเริ่มต้นจำนวนล็อคเติบโตขึ้น

ลองใช้แบบสอบถามที่wiki.postgresql.org/wiki/Lock_dependency_informationเพื่อมุมมองที่ดีขึ้น ไม่ว่าคุณจะมีธุรกรรมที่ยังค้างอยู่หรือลืมกิจกรรมหนัก ๆ ด้วยตารางนี้ที่ทำให้มันยุ่งอยู่เสมอ
Daniel Vérité

อาจเป็นแบบที่ดีกว่าที่ dba.SE
Erwin Brandstetter

คำตอบ:


8

มีความเข้าใจผิดบางประการที่นี่:

บิตแมป nullคือไม่ได้เป็นส่วนหนึ่งของส่วนหัวกอง tuple ตามเอกสาร:

มีส่วนหัวขนาดคงที่ (ครอบครอง 23 ไบต์บนเครื่องส่วนใหญ่) ตามด้วยบิตแมป null ที่เป็นตัวเลือก ...

32 คอลัมน์ที่ไม่สามารถลบได้ของคุณไม่น่าเชื่อถือด้วยเหตุผลสองประการ:

  • บิตแมป null ถูกเพิ่มต่อแถวและเฉพาะในกรณีที่มีค่าจริงNULLในแถวอย่างน้อยหนึ่งค่า คอลัมน์ที่มีค่าเป็นโมฆะไม่มีผลกระทบโดยตรงมีเพียงNULLค่าจริงเท่านั้น หากมีการจัดสรรบิตแมปที่ว่างเปล่ามันจะถูกจัดสรรอย่างสมบูรณ์เสมอ (ทั้งหมดหรือไม่มีเลย) ขนาดที่แท้จริงของบิตแมปโมฆะคือ1 บิตต่อคอลัมน์ปัดเศษขึ้นไบต์ต่อไป ต่อรหัส souce ปัจจุบัน:

    #define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
  • บิตแมป null ถูกปันส่วนหลังจากส่วนหัวของ heap tuple และตามด้วย OID ที่เป็นทางเลือกและจากนั้นข้อมูลแถว การเริ่มต้นของ OID หรือข้อมูลแถวถูกระบุโดยt_hoffในส่วนหัว รหัสแหล่งความคิดเห็นต่อ :

    โปรดทราบว่า t_hoff จะต้องเป็น MAXALIGN หลายรายการ

  • มีหนึ่งไบต์ว่างหลังจากส่วนหัวของ heap tuple ซึ่งมี 23 ไบต์ บิตแมปที่เป็นโมฆะสำหรับแถวสูงสุด8คอลัมน์จึงไม่มีค่าใช้จ่ายเพิ่มเติม ด้วยคอลัมน์ที่ 9 ในตารางt_hoffมีความก้าวหน้าอีกหนึ่งMAXALIGNไบต์ (โดยทั่วไปคือ 8) เพื่อให้อีก 64 คอลัมน์ ดังนั้นชายแดนต่อไปจะอยู่ที่72คอลัมน์

ในการแสดงข้อมูลการควบคุมของคลัสเตอร์ฐานข้อมูล PostgreSQL (รวมถึงMAXALIGN) ตัวอย่างสำหรับการติดตั้ง Postgres 9.3 แบบทั่วไปบนเครื่อง Debian:

    sudo /usr/lib/postgresql/9.3/bin/pg_controldata /var/lib/postgresql/9.3/main

ฉันปรับปรุงคำแนะนำในคำตอบที่เกี่ยวข้องกับคุณยกมา

นอกจากนั้นแม้ว่าALTER TABLEคำสั่งของคุณจะเรียกใช้การเขียนตารางใหม่ทั้งหมด (ซึ่งอาจเป็นไปได้การเปลี่ยนประเภทข้อมูล) 250K นั้นไม่มากเท่าไหร่และจะใช้เวลาไม่กี่วินาทีในเครื่องที่เหมาะสมครึ่งทาง (ยกเว้นแถวใหญ่ผิดปกติ) . 10 นาทีขึ้นไปแสดงว่าเป็นปัญหาที่แตกต่างอย่างสิ้นเชิง คำสั่งของคุณกำลังรอการล็อคบนโต๊ะเป็นไปได้มากที่สุด

จำนวนรายการที่pg_stat_activityเพิ่มขึ้นหมายถึงการทำธุรกรรมที่เปิดกว้างมากขึ้น - ระบุการเข้าถึงพร้อมกันบนโต๊ะ (เป็นไปได้มากที่สุด) ที่ต้องรอให้การดำเนินการเสร็จสิ้น

ภาพบางส่วนในที่มืด

ตรวจสอบการขยายตัวของตารางที่เป็นไปได้ลองแบบนุ่มนวลVACUUM mytableหรือก้าวร้าวมากขึ้นVACUUM FULL mytableซึ่งอาจพบปัญหาการเกิดพร้อมกันเดียวกันเนื่องจากแบบฟอร์มนี้ได้รับการล็อคแบบเอกสิทธิ์ด้วย คุณสามารถลองpg_repackแทน ...

ฉันจะเริ่มต้นด้วยการตรวจสอบปัญหาที่อาจเกิดขึ้นกับดัชนีทริกเกอร์คีย์ต่างประเทศหรือข้อ จำกัด อื่น ๆ โดยเฉพาะประเด็นที่เกี่ยวข้องกับคอลัมน์ โดยเฉพาะดัชนีที่เสียหายอาจมีส่วนเกี่ยวข้อง? ลองREINDEX TABLE mytable;หรือDROPทั้งหมดของพวกเขาและเพิ่มพวกเขาหลังจากที่ในรายการเดียวกันALTER TABLE

ลองรันคำสั่งในตอนกลางคืนหรือเมื่อใดก็ตามที่มีโหลดไม่มาก

วิธีการบังคับเดรัจฉานจะหยุดการเข้าถึงเซิร์ฟเวอร์จากนั้นลองอีกครั้ง:

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


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

ขอบคุณสำหรับคำอธิบายเออร์วิน ฉันคิดว่าคุณพูดถูกดูเหมือนเป็นปัญหาล็อค เมื่อฉันตรวจสอบ pg_stat_activity ฉันจะเห็นว่า ALTER ของฉันมี "กำลังรอ" จริง สิ่งที่ฉันไม่สามารถหาได้คือเหตุใด ALTER จึงไม่สามารถล็อกบนโต๊ะสาเหตุได้แม้ว่าฉันจะไม่สามารถค้นหาคิวรีใด ๆ ได้มันก็ปรากฏว่าไม่ได้รับ แต่ทันทีที่ ALTER ของฉันเริ่มทำงานแบบสอบถามอื่น ๆ ทั้งหมดกำลังรอให้การดำเนินการเสร็จสิ้น ดังนั้นกิจกรรมดูเหมือนจะบ่งชี้ว่า ALTER ล็อคการสืบค้นอื่น ๆ ทั้งหมด แต่ยังระบุว่า ALTER ไม่ได้รับการล็อค ฉันคิดว่ามีบางอย่างที่ฉันไม่เข้าใจดี!

@MatthieuVerrecchia: คุณลองทดสอบที่ Richard แนะนำหรือไม่
Erwin Brandstetter

1
ฉันเพิ่งโคลนโต๊ะของฉันไปที่ใหม่ (ด้วย pg_dump -> pg_sql) คอลัมน์ใหม่ถูกเพิ่มอย่างถูกต้องใน 50ms ซึ่งยืนยันปัญหาการล็อค ยังไม่เข้าใจว่าทำไม ALTER ไม่สามารถล็อคด้วยกิจกรรม db มาตรฐานจริง ๆ

1
@ErwinBrandstetter ฉันได้ติดตามการแนะนำของคุณและลองใช้ VACUUM แล้วก็ REINDEX REINDEX กำลังบล็อกอยู่ด้วยทำให้ไม่สามารถล็อคได้อีก .. หลังจากการตรวจสอบบางครั้งปัญหาก็ง่ายกว่าที่เราคิด .. มี <IDLE> เหลืออีกหนึ่งสัปดาห์ด้วยธุรกรรมที่เปิดอยู่ปัญหาได้รับการแก้ไขแล้วขอบคุณ สำหรับข้อมูลทุกอย่างมีประโยชน์มาก
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.