Commit Graph

15 Commits

Author SHA1 Message Date
ThearchyHelios f774e42463 数据剖析可以同时剖析几张表:剖析设置加「同时剖析的表数」(table_concurrency,1–3,缺省 1,即以前的一张做完再做下一张;上限 3 是给这个源上的分析留出连接池的临时连接),每张表的查询仍一条一条发,所以同一时刻对业务库最多这么多条查询。剖析任务的执行改成按设置开几个执行者,按任务里的顺序一张结束就开始下一张;进度、发过的查询各落在自己那张表上(不再记「正在做的那一张」)。每张表开始前照旧重读数据源:停用、关掉剖析或止损后不再开始新的表,正在做的几张照常做完(止损时剩下的项记止损的原因),都结束后再把没开始的记停下;止损的连续失败、超时比例按几张表的查询合起来算。停止、关停时正在做的几张各自收尾,做完的项照常写进目录,都收完才往上交(等的时候又被停止也等完);一张表让任务整体出错(快照被改动、数据源没了、记结果写库出错)时,另几张按停止收尾、原因写这一句,本进程续不上租约的不写。同时要估同一张表的行数时只估一次(按表加锁,先来的没估成后来的自己估)。同源已有剖析时的 409 说法从「第 x / y 张表」改成「已完成 x / y 张表」。界面:设置表单多一格(单位「张」,提示写明业务库同时要应付几条查询、和分析共用连接),风险说明、卡片悬停、开始前的醒目一句在大于 1 时写明「同时剖析 N 张表、每张表的查询一条一条地发」,预算多一行,这次最多用时按几轮算。测试:同一时刻在途查询不超过设置、每张表仍一条一条发(1/2/3 三种)、几张一起显示进行中并按顺序开始、同时停止各自写进目录、止损后不再开始新表、停用时正在做的做完、一张出错另几张按停止收尾、共享行数只估一次;check-catalog-profile 加一节(预算、估算、说法、两行进行中、表清单)。验收:后端全量 14979 通过;止损那条并发测试单独跑 30 遍、整个剖析任务测试文件并行跑 15 遍都没有偶发;tsc;check-catalog-profile 217 项、check-copy 28 项全过 2026-10-21 09:08:10 +08:00
ThearchyHelios 1a6082f033 大库的对象索引、探查范围和后台探查(next-round 03 A1),schema_view 预筛与按需加入、剖析事实的后端(A2、遗留 e 的底座)
为什么:几千张表的库以前用不了——探查每个源最多取 200 个对象、按数据库列出的顺序截断,同步请求、整份替换、不排队;
落在窗口外的表在目录、look、剖析里被说成「表已不在」。

做了什么:
- db/models_sources.py:source_objects(对象索引一行一个对象:范围、原因、结构指纹与 struct_version、first_seen / last_seen /
  removed_at、reflected_at、按需加入的留痕)、introspect_jobs / introspect_tasks(后台探查任务与逐表状态)。
- data/source_objects.py:每种方言一条字典查询建对象索引(失败退回 Inspector,上限 5 万,截断时不判删除);探查范围规则
  (options.introspect_scope:通配、按 name_key、排除优先、显式列出 / 移出;有目录的表、已发布模板写死 SQL 用到的表 pinned;
  命中超上限拒绝并说出命中数);唯一的 rebuild_schema_cache 从范围内已反射的行物化 schema_cache(形状不变,另加 scope 摘要);
  三种「不在」分开说(removed / missing / out_of_scope / reflect_failed);按需加入(当场只读反射、落盘、留痕、进程内按源加锁)。
- data/introspect_jobs.py:探查改成后台任务(core/job_runtime,lane kind introspect,和同源起草、剖析串行;按批反射、逐表记状态、
  可停止、读完的照样物化;重启标中断不续跑)。
- api/datasources.py:POST /introspect 返回 202 和任务,dry_run 同步只刷新索引、返回命中数;/introspect-jobs 读任务、停止;
  /introspect-scope 读、预览、保存规则;/schema?table= 带剖析事实、说清三种「不在」;DataSourceOut 加 schema_scope、introspect_job。
- schema_view:search_tables(BM25 倒排,遮罩列只用列名,范围外只按名字和注释、权重低一档)、profile_lines(剖析事实一节,
  附「只供写查询参考」,遮罩按渲染那一刻重滤,上传表格快照不一致时不给)、absent_detail。
- look:候选超过 PREFILTER_LIMIT 时只给预筛结果 + 已用到的表 + 一跳关联;点名或挑中范围外的表按需加入(每次查看最多 4 张),
  look 记录加 added_to_scope、prefiltered;表详情带剖析事实。
- tools/datasource:db_schema__ 加 keyword、不传 table 时只列前 50 张;点名范围外的表按需加入(每次运行最多 8 张);查询结果
  照实列「未按目录检查的表」(unchecked_tables,不新增检查规则);建工具时读剖析事实。
- 剖析:_relation_ends 分清「范围外,可以加入」和「表结构里没有」;任务记上传表格的 snapshot_id;last_facts。表助手、/schema
  用同一段剖析事实。
- 目录接口:清单只列范围内,absent_reason 分开说;GET /catalog/search 查对象索引,POST /catalog/scope/add 加入范围。
- 第 1 波留下的一处:check_valid_filter 和 stored_valid_filter 拼有效记录条件时按 quote_name 强制加引号。
- 工具参数纠错:空着的可选参数不止一个时,只认拼写明显接近的那一个(db_schema 多了 keyword 以后 tabel 仍能纠成 table)。
- 测试:3,000 张表的合成库(对象索引、缺省范围超上限拒绝、规则圈 400 张后台读完、停止、重启标中断、和剖析排队、同步起草
  409)、删除与结构版本、Inspector 回退、截断不判删除、范围规则、pinned、方言金样;改了同步探查的老测试改为等任务做完。
2026-10-16 14:17:06 +08:00
ThearchyHelios ad1092900c 剖析的关系覆盖率把对不上类型的键算作没对上;升级前旧说法的剖析备注不再让目录升版本
复核发现两处(C-relation-coverage-inflated、C-profile-note-rewording-bumps-catalog):

一、覆盖率虚高。key_literals 把父列是数字、子列取到的不是整数写法的文字('WALKIN'、'GUEST0')从覆盖率的
分母里拿掉了:散客代号占九成的一列只剩 1 个整数写法的键对上,就测成覆盖率 100%、升为「已核实」,模型的
db_schema、自查、冻结快照都会照这条错的关系写 join。基线上同一份数据是 proposed、覆盖率 3.1%。
- 整数主键里永远没有这些文字,它们照样是子表的键值,算作没对上、留在分母里:
  覆盖率 = 对上的 / (拼进 IN 的 + 按类型就对不上的)。全都不是整数写法时不发父表的核对查询,覆盖率 0%、
  「可能不是这条关系」,不再整条判「无法核对」。
- key_literals 改回 KeyLiterals(literals, unmatchable, unsafe):不能安全拼进 SQL 的值单独计数,不再用
  「取到的 − 拼进的 − 不同类型的」倒推('0012' 和 '12' 写成同一个字面量时会被错说成「类型不支持核对」)。
- 被指向列是日期时间的关系整条跳过,并且在发子表取值查询之前就跳过、不占这张表的查询预算;说明改成
  「各库的时间写法和精度不同,不核对这种关系的覆盖率」——子表一侧也是时间时,以前写的「两端类型不同」不照实。
- 备注里「另有 N 个键值和被指向列的类型不同,未计入」改成「其中 N 个不是整数写法,被指向列是数字,算作没对上」。
- 报告里覆盖率不足的那句「抽样覆盖率 N,保持推断」也改成「覆盖率 N」,和备注一种说法。

二、升级后第一次重新剖析,数据没变也给每张有剖析结论的表升一个版本。剖析备注改了四处说法(抽样覆盖率→
覆盖率、子表抽样→子表取了、(只看前→(按存储顺序只看前、按前 N 行统计→按存储顺序取前 N 行统计),
catalog.same_profile_note 没认成同一句,已发布工作流记下的目录版本对不上,之后每次正式运行都报
catalog.drift。
- same_profile_note 比较前先把这四处固定句式的旧写法换成现在的写法(_LEGACY_PROFILE_WORDING,句式带着前后文
  匹配,不会误换人写的原话);算相同时保留目录里的旧备注,旧说法等结论真变了、重写备注时才换掉。
- 起草时核对有效行过滤写在模型依据后面的那句「剖析核对:按前 N 行统计」同样只认那一句的旧写法。
- MySQL / MariaDB 上新加的排序规则说明、ENUM 列定义里没出现的取值、无效日期个数是新信息,这些备注照常
  升一次版本,要写进发版说明。

测试:test_catalog_profile 加文字键指向整数主键的端到端用例(去掉修复回跑:测成 verified、覆盖率 100%);
test_profile_dialect_units 加覆盖率分母、时间键不发查询、unsafe 计数的单测;test_catalog_semantics 加跨版本
用例(把剖析备注改回旧说法写进目录、同样的数据重新剖析,版本号和目录都不变;去掉规整回跑两条失败)。
2026-10-16 12:02:41 +08:00
ThearchyHelios ee7b8b2f97 剖析与探查的方言修正(C1)和没有真库时的方言验证(C2)
为什么:剖析是全站唯一主动查业务库的地方,以前只在守卫放行和字符串片段两层上测过,从没在真库上跑过。
本机四个容器(PG 16、MySQL 8.4、MariaDB 11、Oracle Free 23)实测,旧的 IN 列表写法在 PostgreSQL 上整数子列
对文字主键直接报 operator does not exist: character varying = integer,关系一条都核对不了。

C1 方言修正:
- IN 列表的字面量按被指向列的类型族写(key_literals):父列文字写 '12',父列数字只收整数写法的值,父列是时间、
  对不上的不拼并在备注里写「两端类型不同」;子表是 CHAR(n) 时去掉补齐的尾随空格。
- 列类型改存按方言编译的完整写法(VARCHAR2(20 CHAR)、NUMBER(10, 0)、ENUM('a','b')、TIMESTAMP WITH TIME ZONE),
  编译不了退回 str()。SQLAlchemy 把 Oracle 的 VARCHAR2 反射成通用 VARCHAR(容器实测),照数据字典写成 VARCHAR2。
  ENUM / SET 另记 enum_values;Oracle 小写带引号的表和列记 quote_name;各索引(含主键)的首列记进
  index_first_columns(下一波取值观察判断能不能对大表发窗口查询)。新探查的快照哈希会变,旧运行封存的不受影响。
- catalog._type_family 认 ENUM / SET 是文字、INTERVAL 不是数字,去掉引号里的取值再认;新增 column_family
  (有 enum_values 的是文字,PostgreSQL 枚举编译出来只有类型名);is_date_column 不再把 ENUM('date') 认成日期列。
- 码值候选:ENUM / SET 不看列名直接算候选,ENUM 列定义里这次没出现的取值也写进码值(含义待填);VARCHAR2(20 CHAR)
  的长度按 20 算;CHAR 码值去尾随空格;MySQL 上写明按排序规则分组、比较(可能不分大小写)。
- 统计信息估出的行数不超过整表统计上限时再跑一次有上限的计数确认,统计过期的大表不再被当成小表做整表统计。
- 日期列的最小值、最大值只看 0001-01-02 到 9999-12-31 之间的值,零日期、占位日期、PG 的 ±infinity 不计入,
  照实写「另有 N 个无效日期未计入」,日期范围里带 invalid 个数(界面显示)。
- 新增取值观察用的方言方法 date_literal / day_trunc / sample_from,以及按日行数、时间窗口里的取值分布、块采样三类
  查询的拼法(窗口上端截在 9999-12-31 之前,不让 infinity 多出一天)。
- 说明文字不再说「抽样」:大表看的是「按存储顺序取前 N 行」;设置项「抽样键值数」改叫「核对键值数」。

C2 验证:
- tests/test_profile_dialect_golden.py:五种方言 × 全部剖析和观察查询的完整 SQL 钉在 tests/fixtures/dialect/,
  sqlglot 逐条解析、过只读守卫,再用 qualify + annotate_types 核对 IN 两边类型族一致(附旧写法的对照)。
- scripts/dialect-it.sh(不进 CI):本机起四个容器,建虚构夹具(保留字列、Oracle 小写带引号的表、CHAR 码值、
  MySQL ENUM、零日期 / infinity / 占位日期、做旧的统计信息、超上限的大表、带索引的日期列),用 AgentLab 自己的
  探查和剖析代码跑全部查询,断言零报错、结论和手算一致。四种库都通过;MariaDB 插入时自己更新行数估算,统计信息
  做不旧,照实打印。把 IN 列表改回旧写法回跑,PG 上照样报出上面那条错误。跑完删容器、留镜像。
2026-10-16 10:25:28 +08:00
ThearchyHelios 6b3c737fb8 数据剖析改成逐表的后台任务:引擎改编排、剖析任务、接口、设置换新键
以前剖析是一次同步长请求,预算按整次算(max_queries 60、max_total_s 120),选 50 张表只做得完前两三张,其余整张记「查询次数用完」;不能停,关掉页面报告就没了,对业务库查了什么无从查。

- data/catalog_profile.py:检查逻辑和 _apply 并入规则原样保留,只换编排。公开的逐表入口 profile_table:先列全检查项(plan_checks,纯函数,范围的 profile_checks、建任务时列的检查项、执行用同一份;遮罩、多列、不在表结构里、指向视图的关系在这里就列成按规则跳过),第一条查询估行数(确知空表整张表跳过),逐项执行、进度回调,整张表结束写目录并和回调在同一次库操作里;停止时做完的项照常写、没做的记 cancelled 保留旧结论。_Runner 拆成整个任务一个的 SourceRunner(只读守卫、单条时限、任务级止损:连续 3 条失败、最近 10 条 7 条超时;最近 6 条 4 条超时提醒;每条查询留痕,SQL 经 normalize_sql 去掉字面量)和每张表一个的 TableBudget(用完只停这张表)。删掉同步的 profile_catalog、挑表前批量估行数(_skip_empty、PROFILE_DEFAULT_TABLES、PROFILE_PROBE_TABLES)和进程内 _RUNNING。设置换成 table_max_queries(1–200,缺省 40)、table_max_s(10–600,缺省 60),旧键 max_queries、max_total_s 启动时从库里删掉(migrate_settings,不折算:旧值按整次算,含义不同),保存时只摘掉不报错(without_legacy)。表助手的 run_query 和起草时核对有效记录条件改走单条查询入口 run_single_query,行为不变。
- data/catalog_profile_jobs.py:剖析任务的建(selected / needed / all 三种范围,排序同前:有待核实关系的在前、使用次数、表结构顺序;挑出 0 张 ProfileNothing)、排队(和同源起草按建立先后串行,waiting_for)、执行(每张表开始前重读数据源:停用或关掉剖析就停下;遮罩按最新设置)、停止、重试、启动标中断不续跑、保留最近 50 个结束的任务(某张表最近一次剖析所在的不删)、last_profile / profile_due 的查询、任务和逐表的接口形状。
- api/catalog.py:加 /profile-jobs(建、active、latest、{job_id}、tasks/{seq}、cancel、retry),登记在 /{table} 前面;删掉 POST /catalog/profile;清单每行加 last_profile、profile_due、profile_due_reason、profile_checks,顶层加 active_profile_job;单表加 last_profile;导入目录、同步起草遇到剖析任务 409 profile_busy。api/coded.py 加 profile_nothing、catalog_profile_finished;api/datasources.py 保存时摘掉旧键;main.py 启动时标中断加设置迁移,关停时停掉进行中的剖析。
- 测试:test_catalog_profile.py、test_catalog_profile_units.py、test_catalog_semantics.py 里打同步接口和旧设置键的改走任务和新键,检查逻辑的断言保留;同步接口的整次总量上限一条改成逐表次数、逐表时长两条。
2026-10-15 18:30:48 +08:00
ThearchyHelios 706f715529 剖析也核实外键关系的基数:外键只保证被指向的键唯一,子表一侧一行还是多行看数据;以前跳过外键,扇出检查对外键来的一对多只能报警告,受管发布挡不住订单关联明细后对订单金额求和。来源、状态、覆盖率不动,只补基数和「用数据核实过」 2026-10-04 03:38:31 +08:00
ThearchyHelios ab9d45c428 数据目录 F2b:剖析报告和目录页读结构化字段,不再从原话里认——服务端最小改动:码值候选的结论带 pending(还有几个含义待填写),关系的结论带 cardinality_checked;报告里「N 个含义待填写」读 pending,基数写「已用数据核实」或「子表一侧未核实」读 cardinality_checked,挑表时跳过的空表读 empty_tables 列出来;表详情的关联关系标出基数已核实;剖析说明不带日期后,码值弹窗的说明后面按这一项的 updated_at 写时间;补后端测试和检查脚本的断言(假答复的 summary 不再写待填写) 2026-10-04 03:06:14 +08:00
ThearchyHelios 5b3839f787 数据目录 F2b:剖析的 409、剖析设置的 422 带机读码,界面不再从原话里认是哪一种——服务端用 api/coded.CodedHTTPException:剖析开始不了的五种情况带 code(profile_disabled、datasource_inactive、schema_missing、profile_busy、snapshot_tampered),保存数据源时剖析设置不合规带 code=profile_settings_invalid 和出错的那一项 field(max_queries……),给人看的那句不变;CodedHTTPException 多一个可选的 field;前端 profileBlockOf、profileFieldOfRejection 只认 code 和 field,没带机读码的旧响应按通用提示处理;补后端测试和检查脚本的断言(伪造的 409、422 都带 code) 2026-10-04 03:03:23 +08:00
ThearchyHelios 88c63bfd41 合入集成分支 feat/data-catalog(d897981,含 F2a 的证据面板、时间线和服务端修复):自动合并,没有冲突;catalog_profile._relation_finding 两边的改动(F2b 的 previous_status、F2a 的 cardinality_checked 写在关系上)互不重叠 2026-10-04 02:52:28 +08:00
ThearchyHelios 99ca98a87d B1 服务端自动挑剖析表不再挑中一批空表:候选里还有待核实(推断)关系的表排在前面,再按使用次数、表结构顺序;挑表时先估行数,确知是空表的跳过并记进 empty_tables(最多估 30 张、最多用掉查询次数上限的一半),估行数的查询算进这张表的查询数;候选全是空表时说明写明是空表 2026-10-04 02:19:26 +08:00
ThearchyHelios 661f6a38d7 A7 剖析写进目录的说明不再写日期:以前写的是 UTC 日期(at[:10]),和界面上按本地时间显示的修改时间对不上;改为「数据剖析:…」,时间以这一项的 updated_at 为准。is_profile_note 同时认升级前带日期的「数据剖析(日期):」;same_profile_note 继续兼容旧数据:只差日期、或一段带日期一段不带的同一结论都算相同,升级后重新剖析不会给每张表升版本 2026-10-04 02:19:26 +08:00
ThearchyHelios 46c3fd3093 A6 扇出检查只在一对多确有其事时报错误:关系人工确认过,或数据剖析在数据上核实过子表一侧的键不唯一(关系上记 cardinality_checked,子表太大没核对的不算)才给 error;只凭外键结构推出的一对多降为 warning,说法改成「可能重复计算」,下一步写确认关联表里每个键只有一行、或先汇总再关联;人工编辑提交里带的 cardinality_checked 不作数;级别说明「结果必然有误」改为不夸大的说法;2B、F1 的测试按新规则更新:外键 + verified → warning,剖析核实过 → error,人工确认 → error 2026-10-04 02:19:26 +08:00
ThearchyHelios 163f3b96b3 数据目录 F2b / B7:剖析报告里关系的结论按实际变化说——原本就是已验证、这次照样核实的写「仍为已验证,覆盖率 x」,从推断升上来的才写「升为已验证」,已验证降回推断的写「降为推断」;服务端最小改动:关系结论多带 previous_status(剖析前的状态),summary 同步写「仍为有确证」;补后端测试和检查脚本的断言 2026-10-04 02:09:47 +08:00
ThearchyHelios c46ff74b8c 数据剖析的测试数据源用完也删掉 2026-10-03 11:10:44 +08:00
ThearchyHelios 6fe21096af 数据剖析接口:POST /catalog/profile 同步剖析,未开启或同一数据源正在剖析时返回 409,返回每张表用的查询数、写入的发现和跳过的原因,记录署名 2026-10-03 11:05:47 +08:00