SQL 实战:反范式化实践 – 提升联表查询效率,减少 JOIN 性能损耗

news2025/1/4 11:51:11

在数据库设计中,范式化(Normalization) 可以减少数据冗余,保持数据一致性。然而,在实际业务中,面对大量的联表查询,范式化结构往往会带来性能瓶颈,尤其是涉及复杂多表 JOIN 操作时。

反范式化(Denormalization) 是一种牺牲部分存储空间以换取查询效率的手段,适用于读多写少、对性能要求较高的场景。
本文将介绍反范式化的核心概念,通过案例展示如何在订单系统中,通过减少 JOIN 提升查询效率,实现高效的数据库设计和查询优化。


一、范式化与反范式化的区别

设计方式特点优点缺点
范式化数据分多张表,符合第三范式(3NF)减少数据冗余,保证数据一致性多表联查时,性能较差
反范式化数据合并存储在一张表或部分冗余字段查询速度快,减少复杂 JOIN 操作数据冗余,更新成本高,可能存在数据不一致

二、反范式化实践场景

适用场景
  • 高频查询场景:查询量大,业务以读操作为主(如电商系统的订单查询)。
  • 数据冗余可接受:存储空间充裕,数据一致性可通过业务逻辑保障。
  • 联表性能瓶颈:涉及大量复杂的 JOIN 操作,查询速度成为瓶颈。

三、实战案例:订单表与用户表反范式化设计


需求描述

在电商系统中,订单表 orders 和用户表 users 之间存在频繁的联表查询。典型需求是查询订单时需要同时展示下单用户的姓名、手机号等信息。


1. 范式化表设计(3NF)

用户表 users

user_idnamephoneaddress
101张三13812345678北京市海淀区
102李四15687654321上海市浦东新区

订单表 orders

order_iduser_idamountorder_date
500110112002024-01-05 14:30:00
50021029002024-01-06 10:00:00

范式化查询

SELECT o.order_id, o.amount, o.order_date, u.name, u.phone  
FROM orders o  
JOIN users u  
ON o.user_id = u.user_id  
WHERE o.order_date >= '2024-01-01';

存在问题
  • 性能瓶颈:当 orders 表记录量达到百万级时,JOIN 查询将非常耗时。
  • 索引不友好:即使为 user_id 建立索引,JOIN 仍需遍历大量记录,影响查询性能。


2. 反范式化设计(减少 JOIN)

思路:在 orders 表中直接冗余存储用户的姓名和手机号,减少用户表的关联查询需求。

反范式化后的订单表 orders

order_iduser_iduser_namephoneamountorder_date
5001101张三1381234567812002024-01-05 14:30:00
5002102李四156876543219002024-01-06 10:00:00

反范式化插入方式
INSERT INTO orders (order_id, user_id, user_name, phone, amount, order_date)  
SELECT 5003, u.user_id, u.name, u.phone, 1500, NOW()  
FROM users u  
WHERE u.user_id = 101;

反范式化查询方式
SELECT order_id, user_name, phone, amount, order_date  
FROM orders  
WHERE order_date >= '2024-01-01';

优点
  • 查询速度大幅提升,无需联表直接返回结果。
  • orders 表中直接存储用户信息,减少 I/O 操作和扫描行数。

缺点
  • 数据冗余增加,用户信息存储在多张表中,更新成本较高。
  • 用户修改手机号或姓名时,需要同步更新 orders 表中所有相关记录。


四、如何保障反范式化后数据一致性

方法 1:触发器同步更新
  • 当用户表数据更新时,通过触发器同步更新订单表的冗余字段。
CREATE TRIGGER after_user_update  
AFTER UPDATE ON users  
FOR EACH ROW  
UPDATE orders  
SET user_name = NEW.name, phone = NEW.phone  
WHERE user_id = OLD.user_id;

方法 2:定期批量更新
  • 通过定时任务或批处理脚本,每日更新订单表中用户信息,保证数据一致性。
UPDATE orders o  
JOIN users u  
ON o.user_id = u.user_id  
SET o.user_name = u.name, o.phone = u.phone  
WHERE o.order_date >= DATE_SUB(NOW(), INTERVAL 7 DAY);


五、反范式化设计的扩展应用场景


1. 日志与审计系统
  • 日志记录通常需要冗余存储用户信息或操作信息,方便快速查询历史记录。

2. 数据仓库(OLAP)
  • 在数据仓库中,反范式化的维度表能够提升查询速度,减少复杂度。
  • 例如,将用户、商品信息直接存入事实表,避免跨库 JOIN 查询。


六、性能对比实验


实验数据
  • orders 表:100 万条订单数据。
  • users 表:10 万用户记录。
  • 测试查询:查询最近 1 个月订单及用户信息。

性能对比结果
查询方式查询时间(秒)查询行数
范式化查询(JOIN users)2.810000
反范式化查询(直接查询 orders)0.710000

结论

  • 在大数据量场景下,反范式化的查询速度提升显著。
  • 反范式化适合读多写少的场景,能够有效减少复杂查询的响应时间。


七、总结

  • 反范式化是提升 SQL 查询效率的重要手段,通过减少复杂的联表操作,显著提高查询速度。
  • 在数据一致性与查询性能之间,需要权衡设计,适度反范式化可以兼顾性能与一致性。
  • 触发器或定时任务可在反范式化设计中保障数据同步,降低维护成本。
  • 高频查询场景下,反范式化可以有效减少数据库压力,是大数据量系统中常用的性能优化策略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2269195.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能商业分析 Quick BI

Quick BI 是阿里云提供的一款智能商业分析(BI)工具,旨在帮助企业快速获取业务洞察、优化决策过程、提升数据分析效率。通过强大的数据可视化和分析功能,Quick BI 能够帮助用户轻松连接多种数据源、创建多维度的报表和仪表盘&#…

uniapp - 小程序实现摄像头拍照 + 水印绘制 + 反转摄像头 + 拍之前显示时间+地点 + 图片上传到阿里云服务器

前言 uniapp,碰到新需求,反转摄像头,需要在打卡的时候对上传图片加上水印,拍照前就显示当前时间日期地点,拍摄后在呈现刚才拍摄的图加上水印,最好还需要将图片上传到阿里云。 声明 水印部分代码是借鉴的…

2024年12月31日Github流行趋势

项目名称:free-programming-books 项目地址url:https://github.com/EbookFoundation/free-programming-books项目语言:HTML历史star数:344575今日star数:432项目维护者:vhf, eshellman, davorpa, MHM5000, …

基于SpringBoot+Vue实现停车场管理系统

作者简介:Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验,被多个学校常年聘为校外企业导师,指导学生毕业设计并参与学生毕业答辩指导,…

Java学习路线:Servlet(一)认识和创建Servlet

目录 创建Servlet WebServlet Servlet的生命周期 认识和使用HttpServlet Servlet是JavaEE的一个标准,他就像JDBC一样,由官方定义了一系列接口,而具体的实现由我们自己编写,最后交给Web服务器如Tomcat来运行我们编写的Servlet…

公路边坡安全监测中智能化+定制化+全面守护的应用方案

面对公路边坡的安全挑战,我们如何精准施策,有效应对风险?特别是在强降雨等极端天气下,如何防范滑坡、崩塌、路面塌陷等灾害,确保行车安全?国信华源公路边坡安全监测解决方案,以智能化、定制化为…

机器人对物体重定向操作的发展简述

物体重定向操作的发展简述 前言1、手内重定向和外部重定向2、重定向原语3、重定向状态转换网络4、连续任意姿态的重定向5、利用其他环境约束重定向总结Reference 前言 对于一些特殊的任务(如装配和打包),对物体放置的位姿由明确的要求&#…

【AndroidAPP】权限被拒绝:[android.permission.READ_EXTERNAL_STORAGE],USB设备访问权限系统报错

一、问题原因 1.安卓安全性变更 Android 12 的安全性变更,Google 引入了更严格的 PendingIntent 安全管理,强制要求开发者明确指定 PendingIntent 的可变性(Mutable)或不可变性(Immutable)。 但是&#xf…

windows系统安装完Anaconda之后怎么激活自己的虚拟环境并打开jupyter

1.在win主菜单中找到Anaconda安装文件夹并打开终端 文件夹内有所有安装后的Anaconda的应用软件和终端窗口启动窗口 点击Anaconda Prompt(Anaconda)就会打开类似cmd的命令终端窗口,默认打开的路径是用户名下的路径 2.激活虚拟环境 使用命令…

django33全栈班2025年004 录入数据

前言 通过前面的学习, 我们已经算是Python基本入门了. 如果你能熟练的掌握的话, 至少让你换台电脑, 在新电脑上搭建Python的开发环境肯定是没问题的. 我们呢也学习了第一行Python代码, 但是我们不知道这行代码是什么意思, 为什么能够运行, 怎么就能输出到控制台呢? 还有, …

Zeotero安装”translate for Zotero“插件

一、Zeotero6translate for Zotero 1.0.28 二、打开Zeotero官网,找到下面圈起来的 三、点击以上连接跳转,Releases windingwind/zotero-pdf-translate 下载 zotero-pdf-翻译.xpi 四、打开zeotero,工具>附加组件(或插件&am…

郑州时空-TMS运输管理系统 GetDataBase 信息泄露漏洞复现

0x01 产品简介 郑州时空-TMS运输管理系统是一款专为物流运输企业设计的综合性管理软件,旨在提高运输效率、降低运输成本,并实现供应链的协同运作。系统基于现代计算机技术和物流管理方法,结合了郑州时空公司的专业经验和技术优势,为物流运输企业提供了一套高效、智能的运输…

小程序信息收集(小迪网络安全笔记~

免责声明:本文章仅用于交流学习,因文章内容而产生的任何违法&未授权行为,与文章作者无关!!! 附:完整笔记目录~ ps:本人小白,笔记均在个人理解基础上整理,…

前端(九)js介绍(2)

js介绍(2) 文章目录 js介绍(2)一、函数1.1函数的两种形式1.2函数的作用域1.3声明与提升 二、bom操作三、dom操作 一、函数 1.1函数的两种形式 //有参函数 //js中的函数只能返回一个值,如果要返回多个需要放在数组或对象中 function func(a,b){return ab } func(1,…

国标GB28181-2022视频平台EasyGBS如何获取设备镜像ID?

在安防监控领域,随着技术的发展和标准的统一,国标GB28181-2022成为了视频监控系统互联互通的重要协议。EasyGBS作为一个遵循该国标的平台,为用户提供了强大的视频监控和管理功能。 在EasyGBS平台的使用过程中,设备镜像ID的获取是一…

【ADAS】高级驾驶辅助系统

自动驾驶入门—ADAS(Advanced Driving Assistance System)高级辅助驾驶系统 一、ADAS的官方介绍 二、信息辅助 1、行车监控类 2、危险预警类 3、驾驶便利类 三、控制辅助 1、紧急应对类 2、驾驶便利类 3、是车道保持类 4、智能灯光类 参考链接&#xff1…

Spring Boot + MinIO 实现分段、断点续传,让文件传输更高效

一、引言 在当今的互联网应用中,文件上传是一个常见的功能需求。然而,传统的文件上传方式在面对大文件或不稳定的网络环境时,可能会出现性能瓶颈和上传失败的问题。 传统文件上传,就像是用一辆小推车搬运大型家具,一…

搭建android开发环境 android studio

1、环境介绍 在进行安卓开发时,需要掌握java,需要安卓SDK,需要一款编辑器,还需要软件的测试环境(真机或虚拟机)。 早起开发安卓app,使用的是eclipse加安卓SDK,需要自行搭建。 目前开…

开发过程优化·自定义鼠标右键菜单

为了改善日常工作中的开发体验,我希望在某个项目目录下点击鼠标右键的快捷菜单,让程序自动为该项目引入一个内部的工具库文件并挂载到项目中。 实现该功能需要组装一些零碎的电脑应用知识,下面徐徐渐进依次说明: 1、在右键菜单中…

搭建ZooKeeper分布式集群

ZooKeeper分布式集群部署旨在通过多节点协作实现高可用性和容错能力。本次实战以三台服务器(master、slave1、slave2)为例,详细介绍了从下载安装到配置启动的全过程。首先,下载并解压ZooKeeper安装包至/usr/local目录,…