`
arlxy
  • 浏览: 39095 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

MySQL中创建及优化索引组织结构的思路

阅读更多

【导读】
通过一个实际生产环境中的数据存取需求,分析如何设计此存储结构,如何操纵存储的数据,以及如何使操作的成本或代价更低,系统开销最小。同时,让更多初学者明白数据存储的表上索引是如何一个思路组织起来的,希望起到一个参考模板的价值作用。

测试用例描述
测试用例为B2C领域,一张用于存储用户选购物品而生成的产品订单信息表,不过去掉一些其他字段,以便用于测试,其表中的数据项也不特别描述,字段意思见表

USE `test`;
DROP TABLE IF EXISTS `test`.`goods_order`;
CREATE TABLE `goods_order`(
`order_id`        INT UNSIGNED      NOT NULL             COMMENT ‘订单单号’,
`goods_id`        INT UNSIGNED      NOT NULL DEFAULT ’0′ COMMENT ‘商品款号’,
`order_type`      TINYINT UNSIGNED  NOT NULL DEFAULT ’0′ COMMENT ‘订单类型’,
`order_status`    TINYINT UNSIGNED  NOT NULL DEFAULT ’0′ COMMENT ‘订单状态’,
`color_id`        SMALLINT  UNSIGNED NOT NULL DEFAULT ’0′ COMMENT ‘颜色id’,
`size_id`         SMALLINT  UNSIGNED NOT NULL DEFAULT ’0′ COMMENT ‘尺寸id’,
`goods_number`    MEDIUMINT  UNSIGNED NOT NULL DEFAULT ’0′ COMMENT ‘数量’,
`depot_id`        INT UNSIGNED  NOT NULL DEFAULT ’0′ COMMENT ‘仓库id’,
`packet_id`       INT UNSIGNED  NOT NULL DEFAULT ’0′ COMMENT ‘储位code’,
`gmt_create`      TIMESTAMP     NOT NULL DEFAULT ’0000-00-00 00:00:00′ COMMENT ‘添加时间’,
`gmt_modify`      TIMESTAMP     NOT NULL DEFAULT ’0000-00-00 00:00:00′ COMMENT ‘更新时间’,
PRIMARY KEY(order_id,`goods_id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 CHARACTER SET ‘utf8′ COLLATE ‘utf8_general_ci’;
 

其中,主键信息:PRIMARY KEY(order_id,`goods_id`),为何主键索引索引字段的顺序为:order_id,`goods_id`,而不是: `goods_id`, order_id呢?原因很简单,goods_id在订单信息表中的重复率会比order_id高,也即order_id的筛选率更高,可以减少扫描索引 记录个数,从而达到更高的效率,同时,下面即将会列出的SQL 也告诉我们,有部分SQL 语句的WHERE字句中只出现order_id字段,为此更加坚定我们必须把字段:order_id作为联合主键索引的头部,`goods_id`为联合主键索引的尾部。

数据存储表设计的小结:
设计用于存储数据的表结构,首先要知道有哪些数据项,也即行内常说的数据流,以及各个数据项的属性,比如存储的数据类型、值域范围及长度、数据完整性等要求,从而确定数据项的属性定义。存储的数据项信息确定之后,至少进行如下三步分析:
l 首先,确定哪些数据项或组合,可以作为记录的唯一性标志;
l 其次,要确定对数据记录有哪些操作,每个操作的频率如何,对网站等类型应用,还需要区分前台操作和后台操作,也即分外部用户的操作,还是内部用户的操作;
l 最后,对作为数据记录操作的条件部分的数据项,分析其数据项的筛选率如何,也即数据项不同值占总数据记录数的比例关心,比例越接近1则是筛选率越好,以及各个值得分布率;
综上所述,再让数据修改性操作优先级别高于只读性操作,就可以创建一个满足要求且性能较好的索引组织结构。
数据的存取设计,就涉及一块非常重要的知识: 关系数据库的基础知识和关系数据理论的范式。对于范式的知识点,特别解释下,建议学到BCNF范式为止,1NF、2NF、3NF和BCNF之间的差别,各 自规避的问题、存在的缺陷都要一清二楚,但是在真实的工作环境中,不要任何存取设计都想向范式靠,用一句佛语准确点表达:空即是色,色即是空。

用于生成测试数据的存储过程代码
创建索引,就离不开表存储的真实数据,为此编写一个存储过程近可能模拟真实生产环境中的数据,同时也方便大家使用此存储过程,在自己的测试环境中,真实感受验证,
存储过程代码:

DELIMITER $$
DROP PROCEDURE IF EXISTS `usp_make_data` $$
CREATE PROCEDURE `usp_make_data`()
BEGIN
DECLARE iv_goods_id INT UNSIGNED DEFAULT 0;
DECLARE iv_depot_id INT UNSIGNED DEFAULT 0;
DECLARE iv_packet_id INT UNSIGNED DEFAULT 0;
 
SET iv_goods_id=5000;
SET iv_depot_id=10;
SET iv_packet_id=20;
 
WHILE iv_goods_id>0
DO
START  TRANSACTION;
WHILE iv_depot_id>0
DO
WHILE iv_packet_id>0
DO
INSERT INTO goods_order(order_id,goods_id,order_type,order_status,color_id,size_id,goods_number,depot_id,packet_id,gmt_create,gmt_modify)
VALUES(SUBSTRING(RAND(),3,8),iv_goods_id,SUBSTRING(RAND(),3,1),SUBSTRING(RAND(),5,1)%2,SUBSTRING(RAND(),3,3),SUBSTRING(RAND(),4,3),SUBSTRING(RAND(),5,2),
iv_depot_id,SUBSTRING(RAND(),4,2)*iv_packet_id,DATE_ADD(NOW(),INTERVAL -SUBSTRING(RAND(),2,3) DAY),DATE_ADD(NOW(),INTERVAL -SUBSTRING(RAND(),3,2) DAY)
);
SET iv_packet_id=iv_packet_id-1;
END WHILE;
SET iv_packet_id=20;
SET iv_depot_id=iv_depot_id-1;
END WHILE ;
 
COMMIT;
SET iv_depot_id=10;
SET iv_goods_id=iv_goods_id-1;
END WHILE ;
END $$
DELIMITER ;
 

业务逻辑描述
l 非注册用户,或网站的注册用户不登陆,都能可选购买物品,生成订单号对应的用户UID为系统默认的;
l 订单与用户UID关联、描述等信息,存储其它的表中,通过订单号的模式关联;
l 用户的订单信息,在未付款之前都可以再修改,付款之后则无法修改;
l 已经付费的订单信息,自动发送到物流部门,进行后续工序的操作。处理完毕之后,会更新订单中涉及物品的存储位置信息;
l 定期读取部分数据到数据仓库分析系统,用于统计分析;
l 个人订单查询,前后台都有;
l 购物记录查询显示;

根据业务规则描述需要使用操纵数据的SQL 语句
(1). EXPLAIN SELECT * FROM goods_order WHERE `order_id`=40918986;
(2). SELECT * FROM goods_order WHERE `order_id` IN (40918986,40717328,30923040…) ORDER BY gmt_modify DESC;
(3). UPDATE goods_order SET gmt_modify=NOW(),…. WHERE `order_id`=40717328 AND goods_id=4248;
(4). SELECT COUNT(*) FROM goods_order WHERE depot_id=0 ORDER BY gmt_modify DESC LIMIT 0,50;
(5). SELECT * FROM goods_order WHERE depot_id=6 AND packet_id=0 ORDER BY gmt_modify DESC LIMIT 0,50;
(6). SELECT COUNT(*) FROM goods_order WHERE goods_id=4248 AND order_status=0 AND order_type=1
(7). SELECT * FROM goods_order WHERE goods_id=4248 AND order_status=0 AND order_type=1 ORDER BY gmt_modify DESC LIMIT 0,50;
(8). SELECT * FROM goods_order WHERE gmt_modify>=’ 2011-04-06’;
8条SQL 语句按触发其执行的用户分类:
l 前台用户点击触发的操作而会执行的SQL 语句为:(1)、(2)、(3);
l 后台内部用户点击触发的操作而会执行的SQL 语句为:(1)、(2)、(3)、(4)、(5)、(6)、(7);
l 后台系统自动定期执行:(4)、(5)、(6)、(7),工作时间正常情况每隔15分钟执行一次,以检查是否有已付款而没有准备货物的订单、是否有收款而未发货的订单等;
l 统计分析系统定期导出数据而执行的SQL 语句为:(8),频率为每24小时一次;
我们再分析上述列出来的SQL ,分为2类,一类是读操作的SQL (备注:SELECT操作),另外一类为修改性操作(备注:UPDATE、DELETE操作),分别如下:
SELECT 的WHERE子句、GROUP BY子、ORDER BY 子句和HAVING 子句中,出现的字段:
(1). order_id
(2). order_id+gmt_modify
(3). depot_id+gmt_modify
(4). depot_id+packet_id+gmt_modify
(5). goods_id+order_status+order_type
(6). goods_id+order_status+order_type+gmt_modify
(7). gmt_modify
修改性操作的WHERE子句中出现的条件字段:
(8). order_id+ goods_id

我们已经存在主键索引:PRIMARY KEY(order_id,`goods_id`),另外考虑到此表数据的操作以SELECT和INSERT为主,UPDATE的SQL 量其次,再根据上述SQL 语句,为此我们可以初步确定需要创建的索引:
ALTER TABLE goods_order
ADD INDEX idx_goodsID_orderType_orderStatus_gmtmodify(goods_id,order_type,order_status,gmt_modify),
ADD INDEX idx_depotID_packetID_gmtmodify(depot_id,packet_id,gmt_modify);

总结:
文章中也分析了为何联合主键索引的顺序为:order_id,`goods_id`,再补充下作为主键的联合索引的字段属性的其他特性:字段值写入之后不变化、字段值长度短且最好为数值类型;
对于编号SQL :(8),每天按更新日期读取一次数据的操作,以采用全表扫描的方式实现,牺牲其数据读取的性能,以减少更新字段修改日期的值而带来的索引维护开销;
对于编号SQL :(4)、(5),考虑到每次都是读取最新的50条记录,以及读取的数据基本上可肯定为热数据,为此不得不牺牲其中一条SQL 的数据读取性能,而少创建一个联合索引,从而减少维护索引字段的IO量;
对于编号SQL :(6)、(7),创建的联合索引,需要特别注意联合索引:idx_goodsID_orderType_orderStatus_gmtmodify(goods_id,order_type,order_status,gmt_modify)中的字段顺序,其中:
l goods_id字段的筛选率高于order_type,order_status,另外gmt_modify字段只出现在ORDER BY子句中,为此只有让goods_id字段作为联合索引的头部,以提高索引的筛选率,从而提高索引的效率,减少逻辑或物理的读。
l order_status字段只有0或1两种值,而order_type有多种,以及根据SQL 语句,必须order_type出现在联合中的位置要比order_status靠近头部;
l gmt_modify字段出现在ORDER BY子句中,为此必须放到联合索引字段的最后;

最后,再梳理一下从需求到设计存储结构,再到编写SQL 和创建索引结构,我们应该做的步骤:
l 整理业务产生的数据流,读取数据的方式;
l 整理清楚数据流中的每个数据项属性信息;
l 分析业务指标,推测需要存储数据的规模(备注:一定要以多少GB 作为容量单位);
l 选择可能用于支持业务的硬件设备和数据库架构;
l 把所有可能操纵数据的条件和操作类型,都整理清楚;
l 分析操纵数据条件字段各自的数据筛选率;
l 权衡各个SQL 的性能和IO量,也即类似于哪个操作权重高一些,那些操作权重适当低一些;
l 创建索引组织结构;
l 收集测试和生产环境的反馈信息,优化索引组织结构;

备注:
本想再用测试环境结合业务的方式,跑一套模拟测试脚本程序,让大家更加直观地看到不同索引组织情况下,相同的SQL 操作及频率,数据库服务器的处理能力和负载变化及对比信息,可惜唯一的服务器无法使用了,只好放弃。对于分析相同的SQL ,走不通索引,其需要的逻辑IO和物理IO量也是一个办法,此次就不分析了,有需要的朋友可以去玩玩,另外建议初学者一定要好好阅读下mysql 手册上的相关章节内容:7.2.6. Index Merge Optimization。

分享到:
评论

相关推荐

    MySQL实战优化-整理版

    以上内容全面涵盖了MySQL实战优化中的关键知识点,从数据库架构设计到具体的优化实践案例,旨在帮助读者深入理解MySQL的工作原理及优化技巧。通过对这些知识点的学习,可以有效地提升MySQL数据库的性能和稳定性。

    mysql sakila数据库样例

    这个文件中,你可以看到各种表的创建语句,包括表的字段、数据类型、约束条件等。例如,`film`表可能包含了电影的基本信息,如ID、标题、年份、时长等;`actor`表记录演员信息,包括ID、姓名等;`rental`表则追踪了...

    mysql数据库学习过程中的一些笔记.zip

    数据库是一个组织数据的集合,表是数据库中的数据结构,由列和行组成。创建表时,我们需要定义列名、数据类型(如INT、VARCHAR、DATE等)以及约束(如主键、外键、唯一性约束等)。 3. **数据类型**: MySQL支持...

    MySQL经典教程

    MySQL可以运行在包括Linux、Unix和Windows在内的多种操作系统上,这使得它成为了各种规模企业及个人项目中不可或缺的数据库解决方案之一。 MySQL的历史和特点对于理解其强大性能和普及程度是非常重要的。MySQL是由...

    柠檬mysql文件资料

    学习者可以通过这些脚本了解MySQL的语法,如查询语言(SELECT)、数据操作(INSERT、UPDATE、DELETE)、事务处理、索引优化、存储过程等核心概念。 综上所述,"柠檬mysql文件资料"为MySQL初学者提供了一个全面的...

    (MySQL).rar_MYSQL学生_大学生 论文 管理系统_大学生论文管理系统_毕业设计_毕业设计 java

    1. 表结构设计:系统中涉及的主要表有用户表(存储学生和教师信息)、论文信息表(存储论文题目、内容、评分等)、附件表(存储论文相关文件)等,通过合理设计字段和关系,实现数据的有效组织。 2. 索引优化:针对...

    毕业设计:基于SSM的mysql-萌宠优购系统(源码 + 数据库)

    在这个系统中,数据库设计应包含商品表、用户表、订单表等多个表,通过合理的表结构和索引来优化查询性能。 【程序】文件夹可能包含了整个项目的源代码,包括Controller、Service、DAO等不同层次的Java类,以及配置...

    Build Your Own Database Driven Web Site Using PHP & MySQL 4th.Edition

    - **索引优化**:讲解索引的作用及其创建方法,提高数据查询效率。 #### 六、结构化的PHP编程 (Structured PHP Programming) 这一章节强调了编程中的良好习惯和规范,帮助开发者编写出易于维护和扩展的代码。主要...

    javaEE_原生Servlet_MySql物流信息网的设计与实现(源码+数据库sql+lun文+视频齐全).rar

    《JavaEE原生Servlet_MySql物流信息网的设计与实现》是一个综合性的项目,它涵盖了Web开发中的多个重要技术,包括JavaEE、Servlet以及MySql数据库。该项目旨在提供一个全面的物流信息管理系统,通过源码、数据库SQL...

    原生Servlet_MySql银行柜员业务绩效考核系统的设计与实现(源码+数据库sql+lun文+视频齐全).rar

    在这个系统中,MySQL可能被用来创建银行柜员的绩效表、用户表和其他业务相关的表,以及执行查询、更新和删除操作。熟悉SQL语言,特别是SQL的DML(数据操纵语言)和DDL(数据定义语言)部分,对于理解和维护数据库...

    数据库课程设计(简单)

    理解索引的工作原理和创建、优化方法,能提升数据库性能。 6. **数据库备份与恢复**:文件名为“程序及数据库备份”提示我们课程设计可能涉及到数据库的备份和恢复策略。备份是为了防止数据丢失,可以定期或在重要...

    xiyoulinux 成员管理系统,基于 Qt 4 + Mysql数据库。.zip

    数据库设计包括实体关系模型(ER模型),表结构设计(如成员表、角色表等),以及相关的数据完整性约束和索引优化。 3. **SQL查询语言**:为了从Mysql数据库中获取、更新或删除数据,开发者需要熟悉SQL语句,包括...

    java书店系统 在线图书商店书城 商城管理系统设计与实现 项目源代码下载 javaweb jsp ssh ssm mysql

    4. **MySQL数据库设计**:设计符合业务需求的数据库模型,学习SQL语句的编写,以及事务处理和索引优化。 5. **商城系统功能实现**:用户注册登录、商品浏览、购物车管理、订单创建和支付、库存控制等核心功能的实现...

    springboot美食菜谱分享平台优化版(源码+sql+论文报告)

    而“lifeshare.sql”文件,根据命名习惯,很可能是数据库的创建和填充脚本,通过执行这个脚本,可以在本地数据库中建立与平台相匹配的数据结构。“lifeShare”可能是源代码的压缩文件,包含Java代码和其他相关资源,...

    javaEE_原生Servlet_MySql企业财务管理系统设计与实现(源码+数据库sql+lun文+视频齐全).rar

    开发者可能使用SQL语句进行数据的增删改查操作,以及数据库设计,如ER图、表结构和索引优化。 4. **企业财务管理系统**:这样的系统通常包括模块如用户管理、账目管理、收支记录、报表分析等。用户管理涉及注册、...

    ASP.NET BS结构的城市酒店入住信息管理系统的设计(源代码+论文).zip

    良好的代码组织结构、文档记录以及模块化设计,有利于后期的维护和功能扩展。 总结,ASP.NET BS结构的城市酒店入住信息管理系统是一个综合运用了Web开发技术、数据库管理、安全控制等多个领域的项目,它的设计与...

    数据库源码

    在这个压缩包中,我们只有一个名为"2.sql"的文件,这很可能是包含SQL语句的文件,用于创建或操作数据库结构。 SQL,即Structured Query Language,是用于管理和处理关系型数据库的标准编程语言。它主要用于执行查询...

    教学管理系统数据库设计

    综上所述,教学管理系统数据库设计是一个复杂的过程,涉及到需求分析、模型建立、数据组织和系统优化等多个环节。有效的数据库设计不仅能保证系统的稳定运行,还能提高教学管理效率,为学校的信息化建设提供有力支持...

Global site tag (gtag.js) - Google Analytics