当前位置: 首页 > article >正文

接手一个烂摊子之后:金仓数据库开发规范实战笔记

接手一个烂摊子之后金仓数据库开发规范实战笔记从一个凌晨三点的故障说起去年接手一个电商中台项目上线才两个月就开始频繁出问题。最严重的一次是凌晨三点订单创建接口大面积超时。排查到最后发现是一张订单表三个月的数据量不到一千万条但每秒钟几百个INSERT操作加上十几个索引的维护开销把服务器的IO完全打满了。打开那张表的定义我惊呆了67个字段其中15个是VARCHAR(500)以上13个索引有一半从来没有被查询用过没有主键用的一个联合唯一索引代替表的fillfactor是默认的100意味着UPDATE会产生大量版本链这不是个案是开发规范缺失的典型后果。接手之后我花了两周时间梳理了一套针对金仓数据库的开发规范现在拿出来分享一下。一、整体设计原则先把大方向定下来1.1 字符集统一金仓支持多种字符集但同一个实例里混用UTF8和GBK会在跨库查询时出现乱码或转换开销。我们的规矩是所有实例统一用UTF8。-- 创建数据库时明确指定字符集CREATEDATABASEorder_db ENCODINGUTF8;1.2 每个应用独立SCHEMA不要把所有表都扔在public里。不同应用、不同模块用独立的SCHEMA隔离权限管理也方便。-- 为订单服务创建独立SCHEMACREATESCHEMAorder_svcAUTHORIZATIONorder_app;-- 设置默认SCHEMASETsearch_pathTOorder_svc,public;1.3 表的硬性约束单表列数不超过80列必须有主键或唯一约束外键必须建索引主外键类型要一致触发器能不用就不用-- 正确的建表示例CREATETABLEorder_svc.t_orders(order_id BIGSERIAL,order_noVARCHAR(32)NOTNULL,user_idINTEGERNOTNULL,amountDECIMAL(12,2)NOTNULL,statusSMALLINTDEFAULT0,created_timeTIMESTAMPDEFAULTCURRENT_TIMESTAMP,updated_timeTIMESTAMPDEFAULTCURRENT_TIMESTAMP,CONSTRAINTpk_orders_order_idPRIMARYKEY(order_id),CONSTRAINTuk_orders_order_noUNIQUE(order_no));1.4 大表处理策略金仓官方建议单表超过5000万条或100GB就要考虑分区或归档。我们在实践中把阈值定得更保守一些——2000万条就触发评估。-- 按月分区示例CREATETABLEorder_svc.t_orders_202501PARTITIONOForder_svc.t_ordersFORVALUESFROM(2025-01-01)TO(2025-02-01);1.5 大对象字段的处理图片、文件不要直接存数据库。金仓虽然支持BLOB/CLOB但大对象和业务数据混在一起IO会成为瓶颈。我们定的规则是文件存OSS或NAS数据库只存路径实在要存LOB单独建一张表存放通过外键关联-- 大对象单独存储CREATETABLEorder_svc.t_order_attachments(attach_id BIGSERIALPRIMARYKEY,order_idBIGINTNOTNULL,file_pathVARCHAR(256)NOTNULL,file_sizeINTEGER,-- 不要在大对象字段上建索引file_contentBLOB);二、命名规范让代码可读可维护命名混乱是很多项目的通病。一套清晰的命名规范能让新人接手时少花一半时间。2.1 表命名格式TB_ 应用名 模块名 表描述-- 示例TB_SHOP_ORDER-- 订单表TB_SHOP_PRODUCT-- 商品表TB_SHOP_USER-- 用户表2.2 索引命名-- 普通索引IDX_表名_字段1_字段2CREATEINDEXidx_order_user_idONt_orders(user_id);-- 唯一索引UID_表名_字段CREATEUNIQUEINDEXuid_order_order_noONt_orders(order_no);-- 主键PK_表名_主键列ALTERTABLEt_ordersADDCONSTRAINTpk_orders_order_idPRIMARYKEY(order_id);2.3 其他对象命名对象类型前缀示例视图V_v_order_summary序列SEQ_seq_order_id函数FUNC_func_calc_amount存储过程P_p_refresh_order临时表TMP_tmp_order_import_20250417_zhang一个重要提醒所有对象名长度不要超过30个字符。金仓对长对象名虽然支持但会给后续维护带来麻烦。三、字段设计选对类型比什么都重要3.1 类型选择的几个原则原则一用对类型别用字符存数字-- 错误用字符存日期create_timeVARCHAR(20)-- ❌-- 正确用DATE类型create_timeDATE-- ✅-- 错误用字符存金额amountVARCHAR(20)-- ❌-- 正确用DECIMALamountDECIMAL(12,2)-- ✅原则二选最小的够用类型-- 状态字段用SMALLINT2字节别用INTEGER4字节statusSMALLINTDEFAULT0-- 年龄用SMALLINT就够了ageSMALLINT-- 定长字符串用CHAR变长用VARCHARcountry_codeCHAR(2)-- 固定2位addressVARCHAR(200)-- 长度不固定原则三能用数值不用字符数值类型比较效率比字符串高得多。这个差异在大表关联查询时特别明显。3.2 填坑经验fillfactor的设置金仓有一个很实用的参数叫fillfactor控制每个数据页的填充率。默认是100表示写满。对于频繁UPDATE的表建议设为80CREATETABLEorder_svc.t_order_status_log(log_id BIGSERIAL,order_idBIGINTNOTNULL,old_statusSMALLINT,new_statusSMALLINT,change_timeTIMESTAMPDEFAULTCURRENT_TIMESTAMP)WITH(fillfactor80);为什么金仓的UPDATE本质上是标记旧行插入新行。如果页面满了新行只能放到其他页面导致读取时需要扫描多个页面。预留20%的空间可以让新行留在同一个页面内这就是HOT更新Heap-Only Tuple性能会好很多。3.3 冗余字段用空间换时间大表关联查询代价很高。适当冗余一些字段可以减少JOIN。-- 订单表里冗余用户姓名避免每次都要关联用户表CREATETABLEt_orders(order_id BIGSERIAL,user_idINTEGERNOTNULL,user_nameVARCHAR(64),-- 冗余字段amountDECIMAL(12,2));代价是更新用户姓名时要同步更新订单表。需要在设计时权衡。四、索引设计少而精4.1 索引数量的控制金仓官方建议单表索引不超过5个。我们内部的标准更严——核心表不超过3个。为什么每个索引都会增加INSERT、UPDATE、DELETE的开销。订单表每插入一条记录要维护主键索引、唯一索引、普通索引…索引越多写入越慢。4.2 索引字段的选择选择性原则把过滤效果最好的字段放前面。假设有两个字段status只有3种值每个值占30%user_id唯一值很多每个值占0.01%那么索引应该是(user_id, status)而不是(status, user_id)。避免冗余索引-- 已经有联合索引CREATEINDEXidx_user_statusONt_orders(user_id,status);-- 这个单字段索引就是冗余的因为联合索引已经能覆盖CREATEINDEXidx_user_idONt_orders(user_id);-- ❌ 不需要4.3 外键必须建索引这是金仓官方特别强调的如果子表外键没有索引父表删除记录时会锁住子表所有记录。-- 子表CREATETABLEt_order_items(item_id BIGSERIAL,order_idBIGINTNOTNULL,product_idINTEGERNOTNULL);-- 外键索引必须建CREATEINDEXidx_order_items_order_idONt_order_items(order_id);4.4 分区表的索引策略金仓的分区索引有个重要原则分区索引必须包含分区列且分区列要放在索引末尾。-- 按月分区的订单表CREATETABLEt_orders(order_id BIGSERIAL,order_noVARCHAR(32),created_dateDATENOTNULL-- 分区键)PARTITIONBYRANGE(created_date);-- 正确的分区索引分区键在最后CREATEINDEXidx_orders_order_noONt_orders(order_no,created_date);4.5 不同索引类型的使用场景金仓支持B-tree、Hash、GIN、GiST、BRIN等多种索引类型。日常开发中B-tree覆盖了90%的场景但有几种情况值得留意BRIN索引适合时间序列表日志、流水索引很小但查询效率不错。-- 日志表用BRIN索引几GB的数据索引可能只有几十MBCREATEINDEXidx_log_createdONt_logUSINGBRIN(created_date);GIN索引适合数组、JSONB字段和全文检索。-- JSONB字段的GIN索引CREATEINDEXidx_products_attrsONt_productsUSINGGIN(attributes);五、SQL编写规范5.1 绑定变量必须用高并发场景下不用绑定变量会导致SQL每次都要硬解析CPU会被占满。-- 错误拼接SQLEXECUTEIMMEDIATESELECT * FROM t_orders WHERE order_id ||v_id;-- 正确用绑定变量EXECUTEIMMEDIATESELECT * FROM t_orders WHERE order_id $1USINGv_id;5.2 避免隐式类型转换-- 假设user_id是INTEGER类型-- 错误传入字符串触发隐式转换SELECT*FROMt_ordersWHEREuser_id123;-- 正确传入数值SELECT*FROMt_ordersWHEREuser_id123;隐式转换会让索引失效这个坑踩一次就记住了。5.3 SELECT只取需要的列-- 错误SELECT *SELECT*FROMt_ordersWHEREorder_id12345;-- 正确只取需要的字段SELECTorder_no,amount,statusFROMt_ordersWHEREorder_id12345;在订单这种宽表上SELECT *会多读大量不需要的数据网络传输和内存占用都更大。5.4 COUNT(*) vs COUNT(列)-- 统计行数用COUNT(*)SELECTCOUNT(*)FROMt_ordersWHEREstatus1;-- 统计某列非NULL值数量用COUNT(列)SELECTCOUNT(user_id)FROMt_orders;COUNT(*)在金仓里优化得很好不要自己写成COUNT(1)或COUNT(主键)。六、连接池管理那些容易被忽视的坑6.1 连接数不是越多越好一个常见的误区并发高就调大max_connections。实际上连接数超过CPU核心数的10倍系统就会开始抖动。因为CPU大部分时间花在上下文切换上而不是真正处理请求。我们定的规则每个CPU核心不超过10个连接。32核的服务器连接数控制在300以内。6.2 防止会话泄漏会话泄漏是开发规范里最容易忽视的问题。异常处理不当连接没释放积少成多把连接池占满。// Java代码示例必须用try-with-resources或finally释放连接try(ConnectionconndataSource.getConnection();PreparedStatementstmtconn.prepareStatement(sql)){// 执行SQL}catch(SQLExceptione){// 记录日志确保连接被关闭log.error(Database error,e);}6.3 登录/注销策略不要为每个SQL请求都创建新连接。连接建立的开销很大TCP握手、认证、分配内存。正确做法使用连接池让连接复用。七、写在最后这套规范推行了半年效果很明显P1级故障从每月3-4次降到了半年1次新人接手项目的上手时间也从2周缩短到了3天。规范的目的是统一认知、减少踩坑不是给开发设障碍。每一条规则的背后都对应着一次真实的线上故障。希望这份总结对你有帮助。

相关文章:

接手一个烂摊子之后:金仓数据库开发规范实战笔记

接手一个烂摊子之后:金仓数据库开发规范实战笔记 从一个凌晨三点的故障说起 去年接手一个电商中台项目,上线才两个月就开始频繁出问题。 最严重的一次是凌晨三点,订单创建接口大面积超时。排查到最后发现是一张订单表,三个月的数据…...

Chrome-QRCode 插件:快速生成与解析二维码的终极指南

Chrome-QRCode 插件:快速生成与解析二维码的终极指南 【免费下载链接】chrome-qrcode chrome-qrcode - 一个 Chrome 浏览器插件,可以生成当前 URL 或选中文本的二维码,或解码网页上的二维码。 项目地址: https://gitcode.com/gh_mirrors/ch…...

别再死记硬背了!我用这套方法,轻松搞定数据库三级模式与SQL基础(附PTA常见考点解析)

数据库三级模式与SQL基础:从死记硬背到理解应用的高效学习法 1. 为什么传统学习方法在数据库学习中失效? 每次翻开数据库原理教材,面对三级模式、数据独立性、SQL分类这些抽象概念,你是否感到一阵眩晕?机械记忆选择题答…...

2026大模型学习路线:从零基础到落地实战,一篇打通转型全路径

2026年,大模型产业正从“概念狂热”走向“工程落地”的深水区,企业对人才的要求不再是“懂原理”,而是“能解决业务问题”。无论是零基础小白、传统程序员,还是35职场人,只要掌握RAG、Agent、轻量化微调三大核心技能&a…...

高效Markdown浏览器插件:轻松预览本地与在线文档的完整解决方案

高效Markdown浏览器插件:轻松预览本地与在线文档的完整解决方案 【免费下载链接】markdown-viewer Markdown Viewer / Browser Extension 项目地址: https://gitcode.com/gh_mirrors/ma/markdown-viewer 还在寻找一款能够优雅渲染Markdown文档的浏览器扩展吗…...

智能社交媒体情感分析:如何用VADER解决非正式文本识别难题

智能社交媒体情感分析:如何用VADER解决非正式文本识别难题 【免费下载链接】vaderSentiment VADER Sentiment Analysis. VADER (Valence Aware Dictionary and sEntiment Reasoner) is a lexicon and rule-based sentiment analysis tool that is specifically attu…...

别再手动改代码了!用STM32CubeMX + RT-Thread Studio 2.1.5 一键生成F4工程(附Scons脚本避坑)

从零构建自动化STM32开发流水线:CubeMX与RT-Thread Studio深度整合实战 当你在凌晨三点盯着KEIL编译器的第47个报错时,某个瞬间是否想过——这些重复的配置工作真的需要手动完成吗?两年前我在汽车电子项目中发现,工程师平均花费37…...

告别手动匹配:Brigadier如何用一行命令解决Boot Camp驱动难题

告别手动匹配:Brigadier如何用一行命令解决Boot Camp驱动难题 【免费下载链接】brigadier Fetch and install Boot Camp ESDs with ease. 项目地址: https://gitcode.com/gh_mirrors/bri/brigadier 还记得那些在Mac上安装Windows时,为了找一个正确…...

Ryujinx模拟器终极实战指南:从零配置到性能优化的完整教程

Ryujinx模拟器终极实战指南:从零配置到性能优化的完整教程 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx 想要在PC上畅玩Switch游戏?Ryujinx模拟器是你的最佳选…...

C# 14原生AOT部署Dify客户端全流程(含dify-sdk源码级patch与AOT友好的HttpClientFactory重构),仅限前500名开发者获取完整CI/CD流水线YAML

第一章:C# 14 原生 AOT 部署 Dify 客户端 实战案例C# 14 引入了更成熟的原生 AOT(Ahead-of-Time)编译支持,使 .NET 应用可脱离运行时独立部署,显著提升启动速度与资源占用效率。本章以构建轻量级 Dify API 客户端为例&…...

GStreamer实战:x264enc插件5种视频格式转换全攻略(附避坑指南)

GStreamer实战:x264enc插件5种视频格式转换全攻略(附避坑指南) 在视频处理领域,H.264编码因其出色的压缩效率和广泛兼容性,至今仍是主流选择。GStreamer作为开源多媒体框架,通过x264enc插件为开发者提供了强…...

从零搭建一个可复用的UVM验证环境:以APB总线为例的保姆级步骤拆解

从零搭建一个可复用的UVM验证环境:以APB总线为例的保姆级步骤拆解 在芯片验证领域,UVM(Universal Verification Methodology)已经成为事实上的行业标准。但对于刚接触UVM的工程师来说,从理论到实践的跨越往往令人望而…...

Dify + LangChain + FastAPI 三端协同集成方案:企业私有化部署必读的6层安全加固清单

第一章:Dify低代码平台集成概述 Dify 是一个开源的 LLM 应用开发平台,支持通过可视化编排与少量代码快速构建 AI 原生应用。其核心价值在于将模型调用、提示工程、RAG 检索、工作流编排等能力封装为可复用组件,使开发者无需从零搭建后端服务即…...

深度学习在物联网中的应用

深度学习在物联网中的应用:智能未来的核心驱动力 物联网(IoT)正以前所未有的速度改变着我们的生活,而深度学习作为人工智能的重要分支,为物联网注入了更强大的智能。通过分析海量传感器数据、优化设备交互以及实现自主…...

3分钟掌握AI语音克隆:Retrieval-based-Voice-Conversion-WebUI终极教程

3分钟掌握AI语音克隆&#xff1a;Retrieval-based-Voice-Conversion-WebUI终极教程 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrieval-bas…...

别再只怪网络了!深入Gradle依赖树,揪出导致kotlin-stdlib-jdk8:1.3.72解析失败的真凶

深入Gradle依赖树&#xff1a;破解kotlin-stdlib-jdk8解析失败的底层逻辑 遇到Gradle构建失败时&#xff0c;许多开发者第一反应是网络问题&#xff0c;但真正的问题往往隐藏在复杂的依赖关系中。本文将带你深入Gradle依赖解析机制&#xff0c;揭示那些被忽视的关键细节。 1. 依…...

通过C#编程开发西门子PLC系统的诊断与故障排查工具

在工业自动化领域&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;是自动化控制系统的核心&#xff0c;广泛应用于各类生产线、设备及工厂的管理控制中。西门子作为全球领先的自动化控制系统提供商&#xff0c;其PLC产品&#xff08;如S7-1200、S7-1500系列&#xff0…...

从‘No tests found’错误出发,聊聊Maven项目里测试代码到底该放哪儿(附最佳实践)

从‘No tests found’错误出发&#xff0c;聊聊Maven项目里测试代码到底该放哪儿&#xff08;附最佳实践&#xff09; 在Java开发的世界里&#xff0c;Maven项目结构就像是一座精心设计的图书馆&#xff0c;而src/main和src/test则是其中最重要的两个分区。但当我们把测试代码…...

郭老师-守住财富的秘诀:心力比运气更重要

守住财富的秘诀&#xff1a;心力比运气更重要“你赚不到钱&#xff0c;更可怕的是你赚到了又赔回去。”&#x1f32a;️ 为什么很多人守不住财富&#xff1f; 1. 误把运气当能力 案例一&#xff1a; 做电商赚了200万 → 贷款买商铺 → 租不出去 → 月供压垮 案例二&#xff1a;…...

安卓开发者的新玩具:在Android Studio里集成DeepSeek模型,打造你的专属AI助手App

安卓开发者的新玩具&#xff1a;在Android Studio里集成DeepSeek模型&#xff0c;打造你的专属AI助手App 作为一名长期奋战在Android开发一线的工程师&#xff0c;我最近发现了一个令人兴奋的新趋势&#xff1a;将本地化AI模型直接集成到移动应用中。这不再是科幻电影里的场景&…...

从西瓜分类到贷款预测:卡方检验在机器学习中的花式应用

卡方检验的跨界实战&#xff1a;从西瓜甜度预测到金融风控建模 当数据科学家面对海量特征时&#xff0c;如何快速识别出最具预测力的变量&#xff1f;在金融风控中&#xff0c;哪些客户特征真正与违约风险相关&#xff1f;农产品品质检测时&#xff0c;哪些外观指标能可靠判断内…...

SSD202开发环境搭建踩坑实录:Ubuntu 16.04下交叉编译工具链配置与内核编译

SSD202开发环境深度构建指南&#xff1a;从工具链配置到内核编译实战 引言&#xff1a;为什么选择Ubuntu 16.04作为SSD202开发环境&#xff1f; 在嵌入式开发领域&#xff0c;环境配置往往比想象中更具挑战性。特别是对于SSD202这类采用ARM Cortex-A7架构的芯片&#xff0c;开发…...

强力浏览器扩展:如何用Markdown Viewer优雅预览本地与在线技术文档

强力浏览器扩展&#xff1a;如何用Markdown Viewer优雅预览本地与在线技术文档 【免费下载链接】markdown-viewer Markdown Viewer / Browser Extension 项目地址: https://gitcode.com/gh_mirrors/ma/markdown-viewer 你是否曾经为无法直接在浏览器中查看Markdown文件而…...

告别纯逻辑:在FPGA里“种”一颗Cortex-M3,打造自定义加密SOC的第一步

在FPGA上构建定制化加密SOC&#xff1a;Cortex-M3软核实战指南 当现成的MCU芯片无法满足特定需求时&#xff0c;FPGA的灵活性为我们打开了一扇全新的大门。想象一下&#xff0c;你可以在硅片上"种植"一个完全定制的处理器系统&#xff0c;就像在数字世界中培育自己的…...

从U-Net到ResNet:拆解TFNet双流网络,看遥感图像融合模型如何‘进化’

从U-Net到ResNet&#xff1a;拆解TFNet双流网络&#xff0c;看遥感图像融合模型如何‘进化’ 遥感图像处理领域的技术演进&#xff0c;就像一场精心设计的接力赛。当U-Net的跳跃连接遇上ResNet的残差思想&#xff0c;在双流网络架构中碰撞出新的火花。TFNet的出现绝非偶然&…...

MAA明日方舟助手:3分钟解放双手的完整自动化解决方案

MAA明日方舟助手&#xff1a;3分钟解放双手的完整自动化解决方案 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手&#xff0c;全日常一键长草&#xff01;| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: https://gitc…...

别再花钱买服务器了!手把手教你用GitLab Pages免费托管个人博客(附.gitlab-ci.yml配置)

零成本打造个人技术博客&#xff1a;GitLab Pages全实战指南 你是否曾经为了展示个人项目而纠结于服务器租用费用&#xff1f;或者因为技术博客的托管问题而迟迟没有开始写作&#xff1f;现在&#xff0c;这些困扰都可以迎刃而解。GitLab Pages提供了一个完全免费的解决方案&am…...

Blazor + OpenTelemetry + eBPF可观测性闭环(某全球TOP3药企FDA审计通关方案,含源码级Span注入日志)

第一章&#xff1a;Blazor OpenTelemetry eBPF可观测性闭环&#xff08;某全球TOP3药企FDA审计通关方案&#xff0c;含源码级Span注入日志&#xff09; 该方案已在某全球TOP3制药企业核心临床试验数据平台落地&#xff0c;通过FDA 21 CFR Part 11 审计验证。其核心在于构建端…...

数据驱动战斗:GBFR Logs如何让你的《碧蓝幻想:Relink》输出提升30%

数据驱动战斗&#xff1a;GBFR Logs如何让你的《碧蓝幻想&#xff1a;Relink》输出提升30% 【免费下载链接】gbfr-logs GBFR Logs lets you track damage statistics with a nice overlay DPS meter for Granblue Fantasy: Relink. 项目地址: https://gitcode.com/gh_mirrors…...

OCR文字识别镜像实战:发票、文档、路牌等图片文字提取

OCR文字识别镜像实战&#xff1a;发票、文档、路牌等图片文字提取 1. 项目概述 基于CRNN模型的OCR文字识别镜像是一款专为日常办公和业务场景设计的智能文字识别工具。它能快速准确地从各类图片中提取文字内容&#xff0c;特别适合处理发票、文档、路牌等常见场景的识别需求。…...