optimize.sql 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. -- ============================================================
  2. -- 数据库优化迁移脚本
  3. -- 目的:
  4. -- 1. 将 drug_chunks.ivfflat 索引升级为 HNSW 索引(检索质量更高)
  5. -- 2. 清理冗余的 embedding(JSON) 列(实际检索用的是 vec pgvector 列)
  6. -- 3. 为 conversations.created_at 和 messages.created_at 添加索引(按时间排序查询)
  7. -- 4. 为 messages.feedback 添加索引(反馈查询过滤)
  8. -- 5. 为 conversations.created_at 添加降序索引(对话历史分页)
  9. -- 6. 为 messages.sources 创建 GIN 索引(来源检索)
  10. -- 注意:此脚本可重复执行(IF NOT EXISTS / IF EXISTS)
  11. -- ============================================================
  12. BEGIN;
  13. -- ------------------------------------------------------------
  14. -- 1. 向量索引升级:IVFFlat → HNSW
  15. -- HNSW 在召回率和查询延迟上都优于 IVFFlat,尤其适合中小规模数据集。
  16. -- lists=10 的 IVFFlat 在数据量增长后检索质量会严重下降。
  17. -- ------------------------------------------------------------
  18. DROP INDEX IF EXISTS public.idx_drug_chunks_vec;
  19. -- HNSW 参数:m=16(连接数),ef_construction=64(构建时搜索宽度)
  20. CREATE INDEX IF NOT EXISTS idx_drug_chunks_vec
  21. ON public.drug_chunks USING hnsw (vec vector_cosine_ops)
  22. WITH (m = 16, ef_construction = 64);
  23. -- ------------------------------------------------------------
  24. -- 2. 清理冗余 embedding(JSON) 列
  25. -- drug_chunks 表同时有 embedding(JSON) 和 vec(pgvector) 两份向量存储,
  26. -- embedding 列完全冗余,从未被 Java/Python 后端使用。
  27. -- 先删除可能依赖该列的索引(实际无),再删除列。
  28. -- ------------------------------------------------------------
  29. ALTER TABLE public.drug_chunks DROP COLUMN IF EXISTS embedding;
  30. -- ------------------------------------------------------------
  31. -- 3. 时间排序索引(解决按时间排序查询的全表扫描问题)
  32. -- ------------------------------------------------------------
  33. -- 对话历史分页:ORDER BY created_at DESC
  34. CREATE INDEX IF NOT EXISTS ix_conversations_created_at
  35. ON public.conversations USING btree (created_at DESC);
  36. -- 消息列表按时间升序:ORDER BY created_at ASC
  37. CREATE INDEX IF NOT EXISTS ix_messages_created_at
  38. ON public.messages USING btree (created_at ASC);
  39. -- ------------------------------------------------------------
  40. -- 4. 反馈查询索引(管理后台反馈列表过滤)
  41. -- ------------------------------------------------------------
  42. CREATE INDEX IF NOT EXISTS ix_messages_feedback
  43. ON public.messages USING btree (feedback)
  44. WHERE feedback IS NOT NULL;
  45. -- ------------------------------------------------------------
  46. -- 5. messages.sources GIN 索引(来源检索)
  47. -- messages.sources 当前是 JSON 类型,先转为 JSONB 再建 GIN 索引
  48. -- (JSON 不支持 GIN 索引,JSONB 支持)
  49. -- ------------------------------------------------------------
  50. DO $$
  51. BEGIN
  52. -- 检查列类型是否为 json(需要转为 jsonb)
  53. IF EXISTS (
  54. SELECT 1 FROM information_schema.columns
  55. WHERE table_name = 'messages' AND column_name = 'sources'
  56. AND data_type = 'json'
  57. ) THEN
  58. ALTER TABLE public.messages ALTER COLUMN sources TYPE jsonb USING sources::jsonb;
  59. RAISE NOTICE '已将 messages.sources 从 json 转为 jsonb';
  60. END IF;
  61. END $$;
  62. CREATE INDEX IF NOT EXISTS ix_messages_sources_gin
  63. ON public.messages USING gin (sources);
  64. -- ------------------------------------------------------------
  65. -- 6. user_progress.last_study_at 索引(按最近学习时间排序)
  66. -- ------------------------------------------------------------
  67. CREATE INDEX IF NOT EXISTS ix_user_progress_last_study_at
  68. ON public.user_progress USING btree (last_study_at DESC)
  69. WHERE last_study_at IS NOT NULL;
  70. COMMIT;
  71. -- ============================================================
  72. -- 验证脚本(执行后可查询以下语句确认优化结果)
  73. -- ============================================================
  74. -- 查看向量索引类型
  75. -- SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'drug_chunks';
  76. --
  77. -- 确认 embedding 列已删除
  78. -- SELECT column_name FROM information_schema.columns WHERE table_name = 'drug_chunks';
  79. --
  80. -- 查看所有新增索引
  81. -- SELECT indexname, indexdef FROM pg_indexes
  82. -- WHERE indexname IN (
  83. -- 'ix_conversations_created_at',
  84. -- 'ix_messages_created_at',
  85. -- 'ix_messages_feedback',
  86. -- 'ix_messages_sources_gin',
  87. -- 'ix_user_progress_last_study_at'
  88. -- );