原文微信公众号:芋道源码

原文地址:如何去写一手好SQL?



1、数据表设计

1.1数据类型

数据类型的选择原则:更简单或者占用空间更小。

  1. 如果长度能够满足,整型尽量使用tinyint、smallint、medium_int而非int。
  2. 如果字符串长度确定,采用char类型。
  3. 如果varchar能够满足,不采用text类型。
  4. 精度要求较高的使用decimal类型,也可以使用BIGINT,比如精确两位小数就乘以100后保存。
  5. 尽量采用timestamp而非datetime。

相比datetime,timestamp占用更少的空间,以UTC的格式储存自动转换时区。

1.2避免空值

MySQL中字段为NULL时依然占用空间,会使索引、索引统计更加复杂。从NULL值更新到非NULL无法做到原地更新,容易发生索引分裂影响性能。尽可能将NULL值用有意义的值代替,也能避免SQL语句里面包含is not null的判断。

1.3text类型优化

由于text字段储存大量数据,表容量会很早涨上去,影响其他字段的查询性能。建议抽取出来放在子表里,用业务主键关联。

2、索引优化

2.1索引分类

  1. 普通索引:最基本的索引。
  2. 组合索引:多个字段上建立的索引,能够加速复合查询条件的检索。
  3. 唯一索引:与普通索引类似,但索引列的值必须唯一,允许有空值。
  4. 组合唯一索引:列值的组合必须唯一。
  5. 主键索引:特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用primary key约束。
  6. 全文索引:用于海量文本的查询,MySQL5.6之后的InnoDB和MyISAM均支持全文索引。由于查询精度以及扩展性不佳,更多的企业选择Elasticsearch。

2.2索引优化

  1. 分页查询很重要,如果查询数据量超过30%,MYSQL不会使用索引。
  2. 单表索引数不超过5个、单个索引字段数不超过5个。
  3. 字符串可使用前缀索引,前缀长度控制在5-8个字符。
  4. 字段唯一性太低,增加索引没有意义,如:是否删除、性别。

合理使用覆盖索引,如下所示:

select login_name, nick_name from member where login_name = ?

login_name, nick_name两个字段建立组合索引,比login_name简单索引要更快。

3、SQL优化

3.1分批处理

分批处理伪代码如下:

int pageNo = 1;
int PAGE_SIZE = 100;
while(true) {
List<Integer> batchIdList = queryList('select id FROM `coupon` WHERE expire_date <= #{currentDate} and status = 1 limit #{(pageNo-1) * PAGE_SIZE},#{PAGE_SIZE}');
if (CollectionUtils.isEmpty(batchIdList)) {
return;
}
update('update status = 0 FROM `coupon` where status = 1 and id in #{batchIdList}')
pageNo ++;
}

3.2操作符<>优化

通常<>操作符无法使用索引,举例如下,查询金额不为100元的订单:

select id from orders where amount != 100;

如果金额为100的订单极少,这种数据分布严重不均的情况下,有可能使用索引。鉴于这种不确定性,采用union聚合搜索结果,改写方法如下:

(select id from orders where amount > 100)
union all
(select id from orders where amount < 100 and amount > 0)

3.3OR优化

在Innodb引擎下or无法使用组合索引,比如:

select id,product_name from orders where mobile_no = '13421800407' or user_id = 100;

OR无法命中mobile_no + user_id的组合索引,可采用union,如下所示:

(select id,product_name from orders where mobile_no = '13421800407')
union
(select id,product_name from orders where user_id = 100);

此时id和product_name字段都有索引,查询才最高效。

3.4IN优化

IN适合主表大子表小,EXIST适合主表小子表大。由于查询优化器的不断升级,很多场景这两者性能差不多一样了。

尝试改为join查询,举例如下:

select o.id from orders o left join user u on o.user_id = u.id where u.level = 'VIP';

采用JOIN如下所示:

select o.id from orders o left join user u on o.user_id = u.id where u.level = 'VIP';

3.5不做列运算

通常在查询条件列运算会导致索引失效,如下所示:

查询当日订单

select id from order where date_format(create_time,'%Y-%m-%d') = '2019-07-01';

date_format函数会导致这个查询无法使用索引,改写后:

select id from order where create_time between '2019-07-01 00:00:00' and '2019-07-01 23:59:59';

3.6避免Select all

如果不查询表中所有的列,避免使用SELECT *,它会进行全表扫描,不能有效利用索引。

3.7Like优化

like用于模糊查询,举个例子(field已建立索引):

SELECT column FROM table WHERE field like '%keyword%';

这个查询未命中索引,换成下面的写法:

SELECT column FROM table WHERE field like 'keyword%';

3.8Join优化

join的实现是采用Nested Loop Join算法,就是通过驱动表的结果集作为基础数据,通过该结数据作为过滤条件到下一个表中循环查询数据,然后合并结果。如果有多个join,则将前面的结果集作为循环数据,再次到后一个表中查询数据。

驱动表和被驱动表尽可能增加查询条件,满足ON的条件而少用Where,用小结果集驱动大结果集。

被驱动表的join字段上加上索引,无法建立索引的时候,设置足够的Join Buffer Size。

禁止join连接三个以上的表,尝试增加冗余字段。

3.9Limit优化

limit用于分页查询时越往后翻性能越差,解决的原则:缩小扫描范围,如下所示:

select * from orders order by id desc limit 100000,10

耗时0.4秒

select * from orders order by id desc limit 1000000,10

耗时5.2秒

先筛选出ID缩小查询范围,写法如下:

select * from orders where id > (select id from orders order by id desc  limit 1000000, 1) order by id desc limit 0,10

耗时0.5秒

如果查询条件仅有主键ID,写法如下:

select id from orders where id between 1000000 and 1000010 order by id desc

耗时0.3秒

4、其他数据库

MySql数据表设计,索引优化,SQL优化,其他数据库的更多相关文章

  1. 架构实战项目心得(十一):基于spring-security-oauth2的mysql数据表设计

    一.建立数据库及数据表结构 CREATE SCHEMA IF NOT EXISTS `oauth2` DEFAULT CHARACTER SET utf8 ; USE `oauth2` ; -- -- ...

  2. redis的key对应mysql数据表设计

    根据用户名来查询用户信息 在关系型数据中,除主键外,还有可能其他列也步骤查询, 如上表中, username 也是极频繁查询的,往往这种列也是加了索引的. 转换到k-v数据中,则也要相应的生成一条按照 ...

  3. 谈谈MySQL数据表的类型(转)

    谈谈MySQL数据表的类型 通常意义上,数据库也就是数据的集合,具体到计算机上数据库可以是存储器上一些文件的集合或者一些内存数据的集合. 我们通常说的MySql数据库,sql server数据库等等其 ...

  4. mysql优化 | 存储引擎,建表,索引,sql的优化建议

    个人对于选择存储引擎,建表,建索引,sql优化的一些总结,给读者提供一些参考意见 推荐访问我的个人网站,排版更好看: https://chenmingyu.top/mysql-optimize/ 存储 ...

  5. php 实现 mysql数据表优化与修复

    <?php $link = mysql_connect("localhost", "root", "") or die("e ...

  6. mysql status关键字 数据表设计中慎重使用

    mysql status关键字  数据表设计中慎重使用

  7. MySQ数据表设计

    数据表概念 数据表是数据库中的基本对象元素,以记录(行)和字段(列)组成的二维结构用于存储数据.数据表由表结构和表内容两部分组成,先建立表结构,然后才能输入数据.数据表结构设计主要包括字段名称.字段类 ...

  8. 设置MySQL数据表主键

    设置MySQL数据表主键: 使用“primary key”关键字创建主键数据列.被设置为主键列不允许出现重复的值,很多情况下与“auto_increment”递增数字相结合.如下SQL语句所示: My ...

  9. MYSQL数据表损坏的原因分析和修复方法小结

    MYSQL数据表损坏的原因分析和修复方法小结 1.表损坏的原因分析 以下原因是导致mysql 表毁坏的常见原因: 1. 服务器突然断电导致数据文件损坏. 2. 强制关机,没有先关闭mysql 服务. ...

随机推荐

  1. MySql Docker 主主配置

    MySql 主主 准备2台Linux服务器,并且在两台服务器上,同时安装docker,国内的同学可以使用aliyun的镜像安装. curl -fsSL https://get.docker.com - ...

  2. 用C#实现模拟双色球中奖程序 控制台应用程序

    前言 这是我在大一第一学期C#的课程设计,要求编写一个模拟双色球彩票的控制台应用程序,用以实现简单的模拟选购彩票. 一.双色球购号号码生成: 1.系统购号:通过"随机数"产生双色球 ...

  3. 强大生产力工具Alfred

    今天要给大家介绍的工具是Alfred,一款Mac下的高效生产力产品.它能做什么呢?简单的说就是:让你能够通过打几个字,就可以完成原本需要一顿操作的事情.举一个简单的栗子:如果我们要在Google搜索一 ...

  4. MP(MyBatis-Plus)的自动填充功能

    什么是自动填充 有些表中会有更新时间.创建时间.更新人或者创建人这些字段. 每次对数据进行新增.删除.修改时都需要对这些字段进行设置.传统的做法是在进行这些操作前,对Entity的字段进行set设置, ...

  5. layui城市三级联动(fesiong / layarea)

    安装 GitHub下载地址:https://github.com/fesiong/layarea.git 使用(html+js) 1. html部分 整个选择器需要使用一个父标签包裹,如下使用了id= ...

  6. 《计算机组成原理 》& 《计算机网络》& 《数据库》 Roadmap for self-taugh student

    计算机组成原理: UCB的这门课绝对是不错的资源. Great Ideas in Computer Architecture (Machine Structures) B站:https://www.b ...

  7. 十四:SQL注入之类型及提交注入

    简要明确参数类型 数字,字符,搜索,json等 简要明确请求方法 GET,POST,COOKIE,REQUEST,HTTP头 其中SQL语句干扰符号:' " % ) } 等,具体查看用法 非 ...

  8. Python基础语法4-运算符

    Python提供了一系列丰富的运算符,包括:  Ø算术运算符  Ø赋值运算符  Ø关系运算符  Ø逻辑运算符 Ø位运算符  Ø三元运算符 Ø身份运算符 Ø成员运算符

  9. 【Spring】Spring的事务管理 - 1、Spring事务管理概述(数据库事务、Spring事务管理的核心接口)

    Spring事务管理概述 文章目录 Spring事务管理概述 数据库事务 什么是Spring的事务管理? Spring对事务管理的支持 Spring事务管理的核心接口 Platform Transac ...

  10. 通过LOGMNR查找程式带入的实际值

    生产库中出现了大量的锁表,需要得到当时程式执行的SQL以及其带入的值 1.查看SQL SELECT SQL_ID FROM V$SESSION WHERE SID=(SELECT FINAL_BLOC ...