一、工具AI – Cline、VS code和MCP1.1 首先在VS code上安装插件Cline 然后安装MCP服务连接doris。1.2 在doris中建立ods表、dwd、dws和ads表。你也可以将所有表的字段写好让cline去帮建表。 我的建立好了。总共13张表。1.3 写个脚本生成数据然后导入到doris中。模拟数据脚本importpymysqlimportpandasaspdimportnumpyasnpfromfakerimportFakerimportrandomfromdatetimeimportdatetime,timedelta# Doris 连接配置 DORIS_CONFIG{host:你自己的ip,port:9030,user:root,password:你root密码,database:gmall,charset:utf8mb4}# 数据生成参数 NUM_USERS500NUM_PRODUCTS200NUM_ORDERS20000NUM_DAYS30START_DATEdatetime(2026,7,1)defgenerate_data():fakeFaker(zh_CN)Faker.seed(42)random.seed(42)# 生成用户users[]foriinrange(1,NUM_USERS1):users.append({user_id:i,username:fake.user_name(),name:fake.name(),gender:random.choice([M,F]),age:random.randint(18,65),province:fake.province(),city:fake.city(),register_date:(START_DATEtimedelta(daysrandom.randint(0,NUM_DAYS))).date()})df_userpd.DataFrame(users)# 生成商品categories[手机数码,家用电器,服装鞋帽,食品饮料,图书文具,运动户外,美妆护肤,母婴用品]products[]foriinrange(1,NUM_PRODUCTS1):priceround(random.uniform(9.9,999.9),2)products.append({product_id:i,product_name:fake.catch_phrase(),category:random.choice(categories),price:price,cost:round(price*random.uniform(0.4,0.7),2),stock:random.randint(10,1000)})df_productpd.DataFrame(products)# 生成订单order_status[待支付,已支付,已发货,已完成]orders[]order_items[]payments[]order_id1for_inrange(NUM_ORDERS):userrandom.choice(users)order_dateSTART_DATEtimedelta(daysrandom.randint(0,NUM_DAYS),hoursrandom.randint(0,23),minutesrandom.randint(0,59))statusrandom.choices(order_status,weights[0.1,0.2,0.25,0.45])[0]num_itemsrandom.randint(1,5)total_amount0items[]for_inrange(num_items):productrandom.choice(products)qtyrandom.randint(1,3)amountround(product[price]*qty,2)total_amountamount items.append({order_id:order_id,product_id:product[product_id],qty:qty,price:product[price],amount:amount})orders.append({order_id:order_id,user_id:user[user_id],order_date:order_date.strftime(%Y-%m-%d %H:%M:%S),total_amount:round(total_amount,2),status:status,pay_date:(order_datetimedelta(minutesrandom.randint(5,120))).strftime(%Y-%m-%d %H:%M:%S)ifstatusin[已支付,已发货,已完成]elseNone,ship_date:(order_datetimedelta(hoursrandom.randint(2,48))).strftime(%Y-%m-%d %H:%M:%S)ifstatusin[已发货,已完成]elseNone,finish_date:(order_datetimedelta(daysrandom.randint(3,10))).strftime(%Y-%m-%d %H:%M:%S)ifstatus已完成elseNone})order_items.extend(items)ifstatusin[已支付,已发货,已完成]:payments.append({payment_id:order_id,order_id:order_id,user_id:user[user_id],amount:round(total_amount,2),pay_method:random.choice([微信支付,支付宝,银行卡]),pay_time:(order_datetimedelta(minutesrandom.randint(5,120))).strftime(%Y-%m-%d %H:%M:%S)})order_id1df_orderpd.DataFrame(orders)df_order_itempd.DataFrame(order_items)df_paymentpd.DataFrame(payments)# 将空字符串替换为 None避免 MySQL 插入空字符串问题# 但我们的数据已经使用 None无需处理returndf_user,df_product,df_order,df_order_item,df_paymentdefinsert_data(df,table_name,conn):ifdf.empty:return0# 将 DataFrame 转为 list of tuples并将 NaN 替换为 Nonedatadf.replace({np.nan:None}).to_dict(records)ifnotdata:return0columnslist(data[0].keys())placeholders,.join([%s]*len(columns))sqlfINSERT INTO{table_name}({,.join(columns)}) VALUES ({placeholders})cursorconn.cursor()# 构建 values 列表values[]forrowindata:values.append(tuple(row[col]forcolincolumns))cursor.executemany(sql,values)conn.commit()cursor.close()returnlen(values)defmain():print(生成数据...)df_user,df_product,df_order,df_order_item,df_paymentgenerate_data()print(f用户{len(df_user)}商品{len(df_product)}订单{len(df_order)}明细{len(df_order_item)}支付{len(df_payment)})# 连接 Dorisconnpymysql.connect(**DORIS_CONFIG)print(开始导入数据...)inserted0insertedinsert_data(df_user,dim_user,conn)insertedinsert_data(df_product,dim_product,conn)insertedinsert_data(df_order,ods_order,conn)insertedinsert_data(df_order_item,ods_order_item,conn)insertedinsert_data(df_payment,ods_payment,conn)conn.close()print(f✅ 成功插入{inserted}行数据到 Doris)if__name____main__:main()导入之后可以稍微看一下没什么大问题基本就ok。二、基础数据准备好之后我们接下来就是重点之重了。因为现在只有ods表和dim表有数据我们要让AI先对我们源数据进行清洗然后再让它们利用AI进行ETL写入到dwd表和dws表和ads表中。上面是提示词ads层写错了不过没关系AI会自动纠正。它会将我的需求拆分成步骤然后按照每一步来进行。我们用AI就是让它辅助我们生成代码然后去监控排查我们的数据质量和BUG或者分析错误日志找到问题所在大部分都是辅助作用。并不是让它去帮我们执行ETL代码哈。这个要分清楚我们的代码始终还是在hadoop里面hive里面或者数据开发平台上去执行。就像这次的我的ETL脚本是在doris执行的它只是创建了脚本。左边可以看到他的进度情况右边可以看到它创建的脚本和数据质量的验证。等一会后就结束了。我们来看一下结果怎么样。烧了113.8KB的token还行。目前我还没支付一分钱还是0的状态参照这张图的前一张0.000。还可以继续苟着使用ads层一张经营日报表就最近三天的日报情况总共32条数据。 另一张是商品的Top5排行榜6000条数据。然后是左下角的那里是它做了一些结果汇总工作订单原表ods2w条数据重复101条去重之后差不多2w。订单明细的6W条数据重复456条。它做的这个结果数据到底准不准我还没验证我明天找个时间验证一下。今天就先到这吧。大家感兴趣的点个赞哈后面有时间再讲一讲关于数据治理的案例这个也挺有意思的三、补充一下数据治理 gmall.ods_order 数据质量检查报告 执行摘要核心发现ods_order表数据质量优秀9 个字段的 19,999 条记录在核心业务字段order_id/user_id/order_date/total_amount/status上 0 空值、0 异常值金额与日期逻辑完全自洽。部分日期空值pay_date/ship_date/finish_date与订单业务状态严格对应属于业务流转的正常现象无需清洗。风险等级评估低无高风险问题仅存在细微可优化的治理项优先级建议持续监控无需立即行动个别项计划修复 详细分析1. 表结构与基础信息项目值完整表名internal.gmall.ods_order总行数19,999列数9分区1 个ods_order数据大小837.67 KB工具get_db_table_list / get_table_schema / get_table_basic_info2. 完整性空值检查核心字段空值统计0 空值100% 完整字段类型空值数空值率order_idbigint00%user_idbigint00%order_datedatetime00%total_amountdecimal(12,2)00%statustext00%etl_timedatetime00%业务日期字段空值与订单状态精确对应字段空值数空值率对应业务状态pay_date2,01210.06% 待支付 2,012 单ship_date6,06430.32% 已支付待支付 4,0522,012finish_date11,05155.26% 未完成订单数✅关键验证空值数完全匹配订单状态流转待支付无支付日期 → 未发货无发货日期 → 未完成无完成日期证明这是业务合理的空值而非数据缺失。3. 准确性异常值检查金额字段total_amount指标值判断最小值10.40✅ 正常0最大值11,582.04✅ 正常平均值2,933.39✅ 合理0/负数记录0✅ 无异常100,000 记录0✅ 无极端异常去重金额数16,354✅ 分布正常日期逻辑一致性交叉验证检查项异常记录数order_date pay_date下单晚于支付0pay_date ship_date支付晚于发货0ship_date finish_date发货晚于完成0order_date ship_date下单晚于发货0✅全部 0 条矛盾记录日期先后顺序完全符合订单生命周期。日期范围合理性字段范围order_date2026-07-01 ~ 2026-07-31当月业务pay_date2026-07-01 ~ 2026-08-01含跨国月底支付etl_time2026-08-22 20:27 ~ 20:32ETL 分批加载 专业建议短期优化可立即执行避免“循环双表”错误访问表统一使用internal.gmall.ods_order三段式命名避免gmall.gmall.ods_order的重复库名错误本次分析在此有所纠正。补充字段注释当前 9 列comment全部为空建议为各字段补充业务注释如 status 枚举、日期含义提升数据可读性。需在 DBA 评估后执行ALTERTABLEinternal.gmall.ods_orderMODIFYCOLUMNstatusTEXTCOMMENT订单状态:待支付/已支付/已发货/已完成;中长期治理规划标准化空值语义pay_date/ship_date/finish_date目前靠业务逻辑空值表达“未发生”建议在文档化约定或引入业务状态码字段便于下游消费时显式过滤。历史数据归档当前仅 1 个分区且无动态分区建议按order_date按月动态分区为后续增量 ETL 和性能优化打基础需评估后执行。最佳实践**该表作为 ODS贴源层质量已达到较高的“随原始数据入库”标准建议在 DWD 层对日期空值进行统一清洗与状态标注。 监控建议指标建议阈值触发动作核心字段空值率0% 立即告警阻断下游 ETL 任务total_amount ≤ 0 记录0 告警人工核查来源数据pay_date 空值与待支付数不匹配偏移 1% 告警触发审查日期逻辑矛盾payship 等0 条告警定位 ETL bugfinish_date 空值率60% 提示观察生命周期是否正常 行动计划数据开发补充字段注释 DDL评估后执行数据建模规划动态分区策略按日期周期监控配置按上述阈值配置质量告警规则预期效果实现 data quality 自动化护航降低下游报表因空值导致的计算偏差风险总结ods_order表数据质量良好属“状态机驱动的合理空值”而非质量问题核心字段 0 空值、金额和日期全无异常可放心供下游使用。6.2 从上面的报告我们也能看出Cline自己在调用一些工具(Skills)时或者查询一些数据时需要填写一些参数它会将参数写错。这可能是一个还需要继续完善的地方。我问它你为何分析过程中会出现避免 gmall.gmall.ods_order 的重复库名的错误请告诉我原因它给我的回答关于出现gmall.gmall.ods_order重复库名的原因说明这个错误源于我在调用元数据探查工具时对参数catalog_name和db_name的语义理解混用了并非数据库本身的问题。技术原因Doris 的命名空间是三级结构catalog_name目录 → database_name数据库 → table_name表SQL 中的三段式写法为internal.gmall.ods_order。internalDoris 内置的默认Catalog目录用于存放和管理 Doris 内部表gmall只是其中的一个Database数据库ods_order才是表名。错误是怎么产生的在分析过程中我调用get_table_schema/get_table_basic_info等元数据工具时错误地把gmall填进了catalog_name参数我传入catalog_name gmall, db_name gmall, table_name ods_order 工具拼接gmall.gmall.ods_order ← cataloggmall, dbgmall, tableods_order而实际系统里并不存在名为gmall的 cataloggmall只是数据库名。所以工具报错Table does not exist/Table gmall.gmall.ods_order not found。正确用法catalog_name internal ← 固定用 Doris 内置目录 db_name gmall ← 真正的数据库名 table_name ods_order ← 表名 拼接结果internal.gmall.ods_order存在对分析结果的影响这些错误只发生在元数据探查阶段的几次调用上属于参数传错后续实际做质量检查时exec_query中我统一使用了正确的internal.gmall.ods_order因此最终的空值/异常值分析结果是完全准确、可信的该问题不影响数据质量检查结论但作为运维经验调用 Doris 工具时catalog 统一填internal库名只填真正的数据库名即可避免此类重复命名错误。我又问它是工具本身的参数有问题还是它自己的问题回答这个错误是我自己调用时记错/混用了参数不是工具的错误我严谨地复盘了整个调用链证据很清楚结论错误在我不在工具关键证据对比调用方式入参结果get_table_schemadb_namegmall,table_nameods_order不传 catalog_name✅ 成功返回 9 字段get_table_basic_infodb_namegmall,table_nameods_order✅ 成功返回gmall.ods_order19999 行exec_querySQL 写成internal.gmall.ods_order✅ 成功get_table_schemacatalog_namegmall,db_namegmall❌ 报gmall.gmall.ods_order不存在get_table_basic_infocatalog_namegmall,db_namegmall❌ 报Table gmall.gmall.ods_order not found关键点只要我不传catalog_name工具默认用当前 catalog internal或者正确只传catalog_nameinternal工具就能成功。而凡是传了catalog_namegmall的工具都会按照三段式拼接规则拼出gmall.gmall.ods_order然后如实报错表不存在。具体来说错在哪Doris 命名空间是三层catalog目录 → database库 → table表internal才是 catalogDoris 内置默认目录gmall只是一个 database我在调用元数据工具时把数据库名gmall误填到了 catalog 参数上好比把省填到了国家字段里工具按规则拼出了不存在的gmall.gmall.ods_order相反exec_query里我一旦写对internal.gmall.ods_order查询立即成功——这正是正确三段式命名的验证与工具问题的区分顺带说明过程中确实有一个工具 bug——analyze_columns因为Decimal类型无法被 JSON 序列化而报错Object of type Decimal is not JSON serializable这个是工具自身的缺陷MCP server 代码没有把 Decimal 转换为可序列化类型但与命名错误无直接关系两者不同源。一句话总结gmall.gmall.ods_order是我在调用时把数据库名 gmall 误当目录名传入导致的属于我自己记错/用错参数工具没问题analyze_columns的 Decimal 错误才是工具 bug。两者我已分辨清楚后续调用已统一使用正确命名internal作为 cataloggmall作为 db空值/异常值分析结果不受影响。/attempt_completion