Heroku Postgres - ยุติการค้นหาที่หยุดทำงาน (ไม่ได้ใช้งานในการทำธุรกรรม)


102

ฉันใช้ Heroku กับตัวเลือก Crane Postgres และฉันกำลังเรียกใช้การสืบค้นบนฐานข้อมูลจากเครื่องในพื้นที่ของฉันเมื่อเครื่องในพื้นที่ของฉันขัดข้อง ถ้าฉันวิ่ง

select * from pg_stat_activity

หนึ่งในรายการมี

<IDLE> in transaction

ในคอลัมน์ current_query_text

ด้วยเหตุนี้ฉันจึงไม่สามารถวางตารางที่ถูกเขียนถึงโดยคำค้นหาที่ถูกยกเลิกได้ ฉันได้ลองใช้ pg_cancel_backend (N) และส่งคืน True แต่ดูเหมือนจะไม่มีอะไรเกิดขึ้น

ฉันจะยุติกระบวนการนี้เพื่อวางตารางได้อย่างไร


1
บางทีคำถามควรเปลี่ยนเป็น "ฉันจะยุติการสืบค้นของตัวเองได้อย่างไรเมื่อไม่มีการเข้าถึงเซิร์ฟเวอร์ postgres หรือ superuser เข้าถึงฐานข้อมูล" ดูเหมือนเป็นคำถามที่ดีมาก ... และฉันไม่รู้คำตอบ
tobixen

คำตอบ:


141

นี่คือคำตอบทั่วไปของ Postgres และไม่เฉพาะเจาะจงสำหรับ heroku


(คำตอบง่ายๆโง่ ๆ สำหรับคำถามนี้อาจเป็น ... เพียงรีสตาร์ท postgresql สมมติว่าไม่เป็นที่ต้องการหรือไม่ใช่ตัวเลือก ... )

ค้นหา PID โดยเรียกใช้ sql นี้:

SELECT pid , query, * from pg_stat_activity
  WHERE state != 'idle' ORDER BY xact_start;

(คำค้นหาอาจต้องการการแก้ไขโดยขึ้นอยู่กับเวอร์ชันของ postgres - ในที่สุดเพียงเลือก * จาก pg_stat_activity) คุณจะพบ pid ในคอลัมน์แรก (ซ้าย) และแถวแรก (บนสุด) น่าจะเป็นข้อความค้นหาที่คุณต้องการยุติ ฉันจะถือว่า pid อยู่ที่ 1234 ด้านล่าง

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

select pg_cancel_backend(1234);

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

select pg_terminate_backend(1234);

หากคุณมีสิทธิ์เข้าถึงเชลล์และสิทธิ์รูทหรือ postgres คุณสามารถทำได้จากเชลล์ ในการ "ยกเลิก" สามารถทำได้:

kill -INT 1234

และเพื่อ "ยุติ" เพียงแค่:

kill 1234

อย่า:

kill -9 1234

... ซึ่งมักจะส่งผลให้เซิร์ฟเวอร์ postgres ทั้งหมดดับลงจากนั้นคุณอาจรีสตาร์ท postgres ได้เช่นกัน Postgres ค่อนข้างมีประสิทธิภาพดังนั้นข้อมูลจะไม่เสียหาย แต่ฉันไม่แนะนำให้ใช้ "kill -9" ไม่ว่าในกรณีใด ๆ :-)


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


ฉันลอง pg_cancel_backend แล้วก็ไม่มีประโยชน์ ฉันไม่มีสิทธิ์เข้าถึงเชลล์และฉันไม่ใช่ superuser ดังนั้นฉันจึงไม่สามารถส่ง SIGKILL โดยใช้ pg_terminate_backend ได้
alan

คุณใช้ postgres เวอร์ชันใด (คำใบ้: select version()) คุณได้รับข้อความแสดงข้อผิดพลาดเมื่อใช้งานpg_cancel_backendหรือไม่?
tobixen

พยายามใช้ pg_cancel_backend ด้วยตัวเองจึงได้รับข้อความแสดงข้อผิดพลาด "ต้องเป็น superuser เพื่อส่งสัญญาณกระบวนการเซิร์ฟเวอร์อื่น" ... หมายความว่าคุณต้องมีการเข้าถึงรูทบนเซิร์ฟเวอร์หรือการเข้าถึงฐานข้อมูลผ่านผู้ใช้ขั้นสูง postgres บางราย (เช่นผู้ใช้ postgres ) เพื่อฆ่าคำถามของคุณเอง ดูเหมือนจะดูดนิดหน่อย :-(
tobixen

1
ปรากฎว่ากระบวนการถูกยกเลิกโดย pg_cancel_backend แต่ข้อความค้นหายังคงแสดงใน pg_stat_activity ชั่วขณะ
อลัน

บางทีอาจเป็นเรื่องเฉพาะสำหรับ Heroku เท่าที่ฉันเห็นภายใต้ postgres ธรรมดามันจำเป็นจริงๆที่จะต้องเป็น superuser เพื่อฆ่ากระบวนการที่ติดขัด (ฉันกำลังทดสอบด้วย "select pg_sleep (3600);" ใน pg 8.4 และฉันได้รับ "ERROR: must be superuser จึงจะส่งสัญญาณได้ กระบวนการเซิร์ฟเวอร์อื่น ๆ ") แม้ว่า "ไม่ได้ใช้งานในการทำธุรกรรม" อีกครั้งก็ไม่เหมือนกัน
tobixen

36

ลองสิ่งนี้:

select pg_terminate_backend(pid int)

เพิ่มเติมเกี่ยวกับเรื่องนี้คุณสามารถหาได้ที่นี่ นี่ควรจะเป็นทางออกที่ 'สะอาดกว่า' ของปัญหานี้มากกว่าการฆ่าด้วยระบบ


โปรดเพิ่มวิธีรับ pid ของคุณในคำตอบของคุณ
mountainclimber11

20

คุณสามารถติดตั้งโปรแกรมheroku-pg-extrasเสริมและรันคำสั่งต่อไปนี้เพื่อรับ PID:

heroku pg:locks --app <your-app>

จากนั้นทำ:

heroku pg:kill <pid> --app <your-app> 

หมายเหตุ : --forceสามารถใช้ตัวเลือกเพื่อออก pg_terminate_backend ซึ่งจะยกเลิกการเชื่อมต่อทั้งหมดสำหรับแบบสอบถามนั้น

ถ้าไม่ได้รายการอะไรลองheroku pg:locksheroku pg:ps

ดูข้อมูลเพิ่มเติมได้ที่
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall


ขอบคุณ. ฉันยังไม่สามารถยุติธุรกรรม / PID ได้แม้ว่า ... คอมพิวเตอร์ของฉันหยุดฮาร์ดแวร์ระหว่างการนำเข้าและฉันไม่สามารถยุติ PID ได้ :(
dimitarvp

-3

เราสามารถใช้สิ่งต่อไปนี้เพื่อให้บรรลุในแบบสอบถามเดียว:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';

ที่จะฆ่าคิวรีที่รันอยู่ทั้งหมดจากนั้นอาจรีสตาร์ท postgres สั่งโดย xact_start และขีด จำกัด 1 และฉันก็เห็นด้วย ... แต่อีกครั้งฉันอยากดูรายการก่อนที่จะฆ่าสุ่มสี่สุ่มห้า
Tobixen

แล้วนี่? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.