پیام خطا را بخوانید؛ معمولاً دقیقاً میگوید چه شده
این درس فهرست مشکلاتی است که تقریباً هر تیمی دیر یا زود با آنها روبهرو میشود؛ برای هرکدام علت و درمان را آوردهایم. اول جدول خلاصه، بعد جزئیات.
| نشانه | علت رایج | درمان کوتاه |
|---|---|---|
| Peer authentication failed for user | اتصال سوکت محلی با روش peer و نام کاربری متفاوت با کاربر سیستمعامل | با -h localhost وصل شوید یا خط local را scram-sha-256 کنید و reload |
| sorry, too many clients already | pool نامحدود، CONN_MAX_AGE دائمی، اتصالهای بیکار | PgBouncer، کاهش workers، بستن اتصالهای بیکار |
| permission denied for schema public | نسخهی 15 به بعد مجوز CREATE را از PUBLIC گرفته | schema اختصاصی یا GRANT CREATE صریح |
| duplicate key value violates unique constraint "..._pkey" بعد از restore | sequence از max(id) عقب مانده | setval |
| deadlock detected | قفل ردیفها با ترتیب متفاوت | ترتیب ثابت، retry |
| could not write to file ... No space left on device | WAL انباشته از slot رهاشده یا archive شکستخورده | حذف slot، درست کردن archive_command |
| کندی تدریجی بدون تغییر کد | bloat یا آمار کهنه | VACUUM/ANALYZE، تنظیم autovacuum |
permission denied for schema public
-- بهترین راه: schema اختصاصی برای برنامه
CREATE SCHEMA app AUTHORIZATION carpet_owner;
ALTER ROLE migrator SET search_path = app;
-- یا: مالک دیتابیس کردن نقش مالک (public از 15 مال pg_database_owner است)
ALTER DATABASE carpet OWNER TO carpet_owner;
-- یا ساده و کمتر امن
GRANT CREATE ON SCHEMA public TO migrator;
duplicate key پس از restore یا ورود دستی داده
SELECT setval(pg_get_serial_sequence('factory.orders', 'id'),
coalesce(max(id), 0) + 1, false)
FROM factory.orders;
این حالت معمولاً وقتی پیش میآید که داده با id صریح وارد شده (مثلاً OVERRIDING SYSTEM VALUE یا COPY فقط داده بدون sequence). تابع pg_get_serial_sequence برای identity هم کار میکند.
دیسک پر از WAL
SELECT slot_name, active, wal_status,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots;
SELECT failed_count, last_failed_wal, last_failed_time FROM pg_stat_archiver;
SELECT pg_drop_replication_slot('standby_old'); -- فقط اگر واقعاً دیگر لازم نیست
هرگز فایلهای داخل pg_wal را دستی پاک نکنید؛ دیتابیس دیگر بالا نمیآید. علت را برطرف کنید؛ پستگرس در checkpoint بعدی خودش پاک میکند.
کندی تدریجی
SELECT relname, n_dead_tup, last_autovacuum, last_autoanalyze, n_mod_since_analyze
FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 10;
VACUUM (VERBOSE, ANALYZE) factory.orders;
اگر n_dead_tup بالاست و VACUUM چیزی پاک نمیکند (در خروجی VERBOSE عبارت «are dead but not yet removable» با عددی بزرگ)، دنبال تراکنش قدیمی، idle in transaction یا slot رهاشده بگردید (فصل ۶).
نکتههایی که کمتر کسی میداند
superuser_reserved_connections(پیشفرض ۳) چند اتصال را برای superuser نگه میدارد؛ حتی وقتی برنامه همه را پر کرده، میتوانید با postgres وارد شوید و اتصالها را ببندید. نسخهی 16reserved_connectionsو نقش pg_use_reserved_connections را هم برای نقشهای غیر superuser آورد.- پیام «could not connect ... Connection refused» با «no pg_hba.conf entry» فرق دارد: اولی یعنی سرور گوش نمیدهد (listen_addresses، فایروال)، دومی یعنی رسیدهاید اما pg_hba راهتان نمیدهد.
- در خطای duplicate key، بخش DETAIL کلید دقیق را نشان میدهد (
Key (id)=(1205) already exists)؛ لاگ برنامهها اغلب فقط خط اول را نگه میدارند و همین جزئیات گم میشود. - متن کامل خطا و SQLSTATE را با
\set VERBOSITY verboseدر psql ببینید؛ کد SQLSTATE (مثل 23505 یا 40P01) برای مدیریت خطا در برنامه پایدارتر از متن پیام است که با زبان سرور عوض میشود. - بعد از restore یک بکاپ قدیمی، اگر برنامه خطای «column does not exist» میدهد، جدول
django_migrationsرا با وضعیت واقعی جدولها مقایسه کنید؛ بکاپ و کد از دو زمان متفاوتاند.