fix_pg_sequences.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. """
  2. 修复 PostgreSQL 序列不同步问题。
  3. 当表中存在手动插入的数据时,自增序列会落后于实际最大 ID,
  4. 导致后续 INSERT 报 UniqueViolation。
  5. """
  6. import os
  7. from dotenv import load_dotenv
  8. load_dotenv()
  9. DB_HOST = os.environ.get("DB_HOST", "localhost")
  10. DB_PORT = int(os.environ.get("DB_PORT", 5432))
  11. DB_USER = os.environ.get("DB_USER", "")
  12. DB_PASSWORD = os.environ.get("DB_PASSWORD", "")
  13. DB_NAME = os.environ.get("DB_NAME", "")
  14. TABLES = [
  15. "spider_task", # collection_task
  16. "ai_conversation",
  17. "spider_result",
  18. "deep_collection",
  19. "ai_model",
  20. "token_usage_log",
  21. "ai_message",
  22. "user",
  23. "spider_source",
  24. "knowledge_import_task",
  25. ]
  26. def fix_sequences():
  27. import psycopg2
  28. uri = f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
  29. print(f"Connecting to {DB_HOST}:{DB_PORT}/{DB_NAME} as {DB_USER}...")
  30. conn = psycopg2.connect(
  31. host=DB_HOST,
  32. port=DB_PORT,
  33. user=DB_USER,
  34. password=DB_PASSWORD,
  35. dbname=DB_NAME,
  36. )
  37. conn.autocommit = True
  38. cur = conn.cursor()
  39. fixed = []
  40. skipped = []
  41. for table in TABLES:
  42. seq = f"{table}_id_seq"
  43. try:
  44. # 检查序列是否存在
  45. cur.execute(
  46. "SELECT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_name = %s)",
  47. (seq,),
  48. )
  49. exists = cur.fetchone()[0]
  50. if not exists:
  51. skipped.append(table)
  52. continue
  53. # 获取当前序列值和表最大 ID
  54. cur.execute(f"SELECT last_value FROM {seq}")
  55. seq_val = cur.fetchone()[0]
  56. cur.execute(f"SELECT COALESCE(MAX(id), 0) FROM {table}")
  57. max_id = cur.fetchone()[0]
  58. if max_id > seq_val:
  59. cur.execute(f"SELECT setval('{seq}', {max_id})")
  60. fixed.append(f"{table}: seq {seq_val} -> {max_id}")
  61. else:
  62. skipped.append(f"{table}: seq={seq_val}, max_id={max_id} (OK)")
  63. except Exception as e:
  64. skipped.append(f"{table}: ERROR - {e}")
  65. cur.close()
  66. conn.close()
  67. print("\n--- 修复结果 ---")
  68. for item in fixed:
  69. print(f" [FIXED] {item}")
  70. for item in skipped:
  71. print(f" [OK ] {item}")
  72. if fixed:
  73. print(f"\n共修复 {len(fixed)} 个表的序列。")
  74. else:
  75. print("\n所有序列均正常,无需修复。")
  76. if __name__ == "__main__":
  77. fix_sequences()