热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL优化第一天

MySQL如何优化表的设计合理化(符合3NF)添加适当索引(index)[四种:普通索引、主键索引、唯一索引unique、全文索引]SQ

MySQL如何优化

表的设计合理化(符合3NF)

添加适当索引(index) [四种: 普通索引、主键索引、唯一索引unique、全文索引]

SQL语句优化

分表技术(水平分割、垂直分割)

读写[写: update/delete/add]分离

存储过程 [模块化编程,可以提高速度]

对mysql配置优化 [配置最大并发数my.ini, 调整缓存大小 ]

mysql服务器硬件升级

定时的去清除不需要的数据,定时进行碎片整理(MyISAM)

数据库设计

什么是数据库范式

为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。

数据库三大范式

第一范式:1NF是对属性的原子性约束,要求属性(列)具有原子性,不可再分解;(只要是关系型数据库都满足1NF)

第二范式:2NF是对记录的惟一性约束,表中的记录是唯一的, 就满足2NF, 通常我们设计一个主键来实现,主键不能包含业务逻辑。

第三范式:3NF是对字段冗余性的约束,它要求字段没有冗余。 没有冗余的数据库设计可以做到。

但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是: 在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。

分表分库

垂直拆分

垂直拆分就是要把表按模块划分到不同数据库表中(当然原则还是不破坏第三范式),这种拆分在大型网站的演变过程中是很常见的。当一个网站还在很小的时候,只有小量的人来开发和维护,各模块和表都在一起,当网站不断丰富和壮大的时候,也会变成多个子系统来支撑,这时就有按模块和功能把表划分出来的需求。其实,相对于垂直切分更进一步的是服务化改造,说得简单就是要把原来强耦合的系统拆分成多个弱耦合的服务,通过服务间的调用来满足业务需求看,因此表拆出来后要通过服务的形式暴露出去,而不是直接调用不同模块的表,淘宝在架构不断演变过程,最重要的一环就是服务化改造,把用户、交易、店铺、宝贝这些核心的概念抽取成独立的服务,也非常有利于进行局部的优化和治理,保障核心模块的稳定性

垂直拆分用于分布式场景。

水平拆分

上面谈到垂直切分只是把表按模块划分到不同数据库,但没有解决单表大数据量的问题,而水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。例如像计费系统,通过按时间来划分表就比较合适,因为系统都是处理某一时间段的数据。而像SaaS应用,通过按用户维度来划分数据比较合适,因为用户与用户之间的隔离的,一般不存在处理多个用户数据的情况,简单的按user_id范围来水平切分

通俗理解:水平拆分行,行数据拆分到不同表中, 垂直拆分列,表数据拆分到不同表中

水平分割案例

思路:在大型电商系统中,每天的会员人数不断的增加。达到一定瓶颈后如何优化查询。

可能大家会想到索引,万一用户量达到上亿级别,如何进行优化呢?

使用水平分割拆分数据库表。

如何使用水平拆分数据库

使用水平分割拆分表,具体根据业务需求,有的按照注册时间、取摸、账号规则、年份等。

 

使用取摸方式分表

首先我创建三张表 user0 / user1 /user2 , 然后我再创建 uuid表,该表的作用就是提供自增的id。

 







create table user0(

id int unsigned primary key ,

name varchar(32) not null default '',

pwd  varchar(32) not null default '')

engine=myisam charset utf8;

 

create table user1(

id int unsigned primary key ,

name varchar(32) not null default '',

pwd  varchar(32) not null default '')

engine=myisam charset utf8;

 

create table user2(

id int unsigned primary key ,

name varchar(32) not null default '',

pwd  varchar(32) not null default '')

engine=myisam charset utf8;

 

 

create table uuid(

id int unsigned primary key auto_increment)engine=myisam charset utf8;

 


创建一个demo项目


POM文件








&#160;&#160;&#160;&#160; <parent>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <groupId>org.springframework.bootgroupId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <artifactId>spring-boot-starter-parentartifactId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <version>1.3.3.RELEASEversion>

&#160;&#160;&#160;&#160; parent>

&#160;&#160;&#160;&#160; <dependencies>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <groupId>org.springframework.bootgroupId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <artifactId>spring-boot-starter-jdbcartifactId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <groupId>org.springframework.bootgroupId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <artifactId>spring-boot-starterartifactId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <groupId>org.springframework.bootgroupId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <artifactId>spring-boot-starter-testartifactId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <scope>testscope>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <groupId>mysqlgroupId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <artifactId>mysql-connector-javaartifactId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <dependency>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <groupId>org.springframework.bootgroupId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <artifactId>spring-boot-starter-webartifactId>

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dependency>

&#160;&#160;&#160;&#160; dependencies>


Service代码








@Service

publicclass UserService {

&#160;

&#160;&#160;&#160;&#160; @Autowired

&#160;&#160;&#160;&#160; private JdbcTemplate jdbcTemplate;

&#160;

&#160;&#160;&#160;&#160; public String regit(String name, String pwd) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // 1.先获取到自定增长ID

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String idInsertSQL = "INSERT INTO uuid VALUES (NULL);";

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; jdbcTemplate.update(idInsertSQL);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Long insertId = jdbcTemplate.queryForObject("select last_insert_id()", Long.class);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // 2.判断存储表名称

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String tableName = "user" + insertId % 3;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // 3.注册数据

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String insertUserSql = "INSERT INTO " + tableName + " VALUES (&#39;" + insertId + "&#39;,&#39;" + name + "&#39;,&#39;" + pwd

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + "&#39;);";

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println("insertUserSql:" + insertUserSql);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; jdbcTemplate.update(insertUserSql);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return"success";

&#160;&#160;&#160;&#160; }

&#160;

&#160;&#160;&#160;&#160; public String get(Long id) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String tableName = "user" + id % 3;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String sql = "select name from " + tableName + "&#160; where id="+id;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println("SQL:" + sql);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String name = jdbcTemplate.queryForObject(sql, String.class);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; returnname;

&#160;&#160;&#160;&#160; }

&#160;

}

&#160;

Controller








@RestController

publicclass UserController {

&#160;&#160;&#160;&#160; @Autowired

&#160;&#160;&#160;&#160; private UserService userService;

&#160;

&#160;&#160;&#160;&#160; @RequestMapping("/regit")

&#160;&#160;&#160;&#160; public String regit(String name, String pwd) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; returnuserService.regit(name, pwd);

&#160;&#160;&#160;&#160; }

&#160;

&#160;&#160;&#160;&#160; @RequestMapping("/get")

&#160;&#160;&#160;&#160; public String get(Long id) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String name = userService.get(id);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; returnname;

&#160;&#160;&#160;&#160; }

&#160;

}

&#160;

配置文件








spring.datasource.url=jdbc:mysql://localhost:3306/test

spring.datasource.username=root

spring.datasource.password=root

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

&#160;

&#160;

&#160;

SQL优化

如何从一个大项目中,迅速的定位执行速度慢的语句. (定位慢查询)

show status

使用show status使用show status查看MySQL服务器状态信息

常用命令



















--mysql数据库启动了多少时间

show status like &#39;uptime&#39;;

show&#160; stauts like &#39;com_select&#39;&#160; show stauts like &#39;com_insert&#39; ...类推 update&#160; delete(显示数据库的查询,更新,添加,删除的次数)

show [session|global] status like .... 如果你不写&#160; [session|global] 默认是session 会话,指取出当前窗口的执行,如果你想看所有(从mysql 启动到现在,则应该 global)

//显示到mysql数据库的连接数

show status like &#160;&#39;connections &#39;;

//显示慢查询次数

show status like &#39;slow_queries&#39;;

&#160;

慢查询


什么是慢查询

&#160; MySQL默认10秒内没有响应SQL结果,则为慢查询

可以去修改MySQL慢查询默认时间

如何修改慢查询








--查询慢查询时间

show variables like &#39;long_query_time&#39;;

--修改慢查询时间

set long_query_time=1; ---但是重启mysql之后,long_query_time依然是my.ini中的值

&#160;

如何定位慢查询


初始化测试数据


创建表结构







/*部门表*/

CREATE TABLE dept(

deptno MEDIUMINT&#160;&#160; UNSIGNED&#160; NOT NULL&#160; DEFAULT 0,&#160; /*编号*/

dname VARCHAR(20)&#160; NOT NULL&#160; DEFAULT "", /*名称*/

loc VARCHAR(13) NOT NULL DEFAULT "" /*地点*/

) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

/*员工表*/

CREATE TABLE emp

(empno&#160; MEDIUMINT UNSIGNED&#160; NOT NULL&#160; DEFAULT 0, /*编号*/

ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/

job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/

mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/

hiredate DATE NOT NULL,/*入职时间*/

sal DECIMAL(7,2)&#160; NOT NULL,/*薪水*/

comm DECIMAL(7,2) NOT NULL,/*红利*/

deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/

)ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

&#160;

&#160;

&#160;

/*薪水*/

CREATE TABLE salgrade

(

grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,

losal DECIMAL(17,2)&#160; NOT NULL,

hisal DECIMAL(17,2)&#160; NOT NULL

)ENGINE=MyISAM DEFAULT CHARSET=utf8;

&#160;

/*测试数据*/

&#160;

INSERT INTO salgrade VALUES (1,700,1200);

INSERT INTO salgrade VALUES (2,1201,1400);

INSERT INTO salgrade VALUES (3,1401,2000);

INSERT INTO salgrade VALUES (4,2001,3000);

INSERT INTO salgrade VALUES (5,3001,9999);

&#160;

创建函数







create function rand_string(n INT)

returns varchar(255) #该函数会返回一个字符串

begin

#chars_str定义一个变量 chars_str,类型是 varchar(100),默认值&#39;abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ&#39;;

&#160;declare chars_str varchar(100) default

&#160;&#160; &#39;abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ&#39;;

&#160;declare return_str varchar(255) default &#39;&#39;;

&#160;declare i int default 0;

&#160;while i

&#160;&#160; set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));

&#160;&#160; set i = i + 1;

&#160;&#160; end while;

&#160; return return_str;

&#160; end

&#160;

create FUNCTION rand_num()

RETURNS int(5)

BEGIN

&#160;DECLARE i int default 0;

&#160;set i =floor(10+RAND()*500);

&#160;return i;

END


创建存储过程







delimiter $$

create procedure insert_emp(in start int(10),in max_num int(10))

begin

declare i int default 0;

#set autocommit =0 把autocommit设置成0

&#160;set autocommit = 0;&#160;

&#160;repeat

&#160;set i = i + 1;

&#160;insert into emp values ((start+i) ,rand_string(6),&#39;SALESMAN&#39;,0001,curdate(),2000,400,rand_num());

&#160; until i = max_num

&#160;end repeat;

&#160;&#160; commit;

&#160;end $$

执行存储过程

call insert_emp (100001,40000000);&#160;

&#160;

如何将慢查询定位到日志中

在默认情况下,我们的mysql不会记录慢查询,需要在启动mysql时候,指定记录慢查询才可以

bin\mysqld.exe --safe-mode&#160; --slow-query-log [mysql5.5 可以在my.ini指定](安全模式启动,数据库将操作写入日志,以备恢复)

bin\mysqld.exe –log-slow-queries=d:/abc.log [低版本mysql5.0可以在my.ini指定]

先关闭mysql,再启动, 如果启用了慢查询日志,默认把这个文件放在

my.ini 文件中记录的位置

#Path to the database root

datadir=" C:/ProgramData/MySQL/MySQL Server 5.5/Data/"

&#160;

图片MySQL优化第一天 - 文章图片

MySQL优化第一天 - 文章图片

MySQL优化第一天 - 文章图片

MySQL优化第一天 - 文章图片

MySQL优化第一天 - 文章图片

&#160;


推荐阅读
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 2018年人工智能大数据的爆发,学Java还是Python?
    本文介绍了2018年人工智能大数据的爆发以及学习Java和Python的相关知识。在人工智能和大数据时代,Java和Python这两门编程语言都很优秀且火爆。选择学习哪门语言要根据个人兴趣爱好来决定。Python是一门拥有简洁语法的高级编程语言,容易上手。其特色之一是强制使用空白符作为语句缩进,使得新手可以快速上手。目前,Python在人工智能领域有着广泛的应用。如果对Java、Python或大数据感兴趣,欢迎加入qq群458345782。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
author-avatar
风中冰雨
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有