Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >浅谈数据库优化

浅谈数据库优化

作者头像
灬沙师弟
发布于 2024-02-22 05:26:30
发布于 2024-02-22 05:26:30
21200
代码可运行
举报
文章被收录于专栏:Java面试教程Java面试教程
运行总次数:0
代码可运行

浅谈数据库优化

面试官: 平时项目中用到了哪些数据库优化的方法?

了不起: 建索引

面试官: 除了建索引呢?

优化策略

数据类型优化

数据类型的优化主要是指选取什么类型。需要遵循“小而简单”的原则。因为这样的数据类型占用的内存、磁盘更低,CPU处理时间也更少。举个常见的例子。

1、日期类型选择。MySQL中关于时间类型,MySQL中最小精度是秒。有Datetime、Timestamp和int三种类型类型来存储时间,个人推荐使用Datetime。Datetime时间类型存储的范围比Timestamp更大,而且Timestamp因时区不同而不同,int时间显示不够直观。

2、指定最大显示宽度,不会改变存储空间。显示宽度与存储大小或类型包含的值的范围无关。也就是说对存储和计算来讲,指定了长度的int(1)和int(12)是相同的。

3、 unsigned(无符号)属性不允许有负值,这可以使正数存储范围扩大一倍,比如UNSIGNED TINYINT存储的范围是0 - 255,TINYINT的范围是-128 ~ 127。所以在没有用到负数的情况下,建议用unsigned(无符号)。

4、存储IP地址时最好使用无符号整数,而不是字符串,这样可以节省存储空间,Inet_ATON()将带点儿的IP转为数字,而Inet_NTOA可将数字转为IP。

5、对一些精度要求比较高的数据,有人建议使用DECIMAL,decimal需要额外的空间和计算开销。建议使用BIGINT,在需要精确到千分之一的时候,可以先乘以1000,再用BIGINT存。

6、通常情况下列最好为NOT NULL, NULL 会使得索引失效。

7、当数据量比较大的时候,不推荐使用alter table。因为alter table 会创建一个新结构的表,并把老表中的数据插入到新表中。

8、不推荐使用Enum。因为枚举类型是固定的字符串列表,添加和删除的时候需要使用alter table命令。

索引优化

MySQL优化最重要建立索引,建立好的索引可以起到事半功倍的效果。

索引结构与算法

首先要介绍索引的结构。索引数据结构与原理可以参考这篇文章:MySQL索引背后的数据结构及算法原理。这里不做过多的解释。看过这篇文章之后抛出一个问题:为什么不用Hash索引,而是使用B-Tree索引结构,理论上Hash索引的查询时间复杂度只有O(1)。这里主要有以下5点原因:1、hash函数计算后的结果,是随机的,如果是在磁盘上放置数据。比主键为id为例, 那么随着id的增长, id对应的行,在磁盘上随机放置. 2、不法对范围查询进行优化。3、无法利用前缀索引. 比如 在btree中, field列的值“hellopworld”,并加索引。查询 xx=helloword,自然可以利用索引, xx=hello,也可以利用索引,(左前缀索引)。因为hash(‘helloword’),和hash(‘hello’),两者的关系仍为随机。4、排序也无法优化。5、必须回行.就是说 通过索引拿到的只是数据位置,而不是数据值,必须回到表中取数据。

索引注意点

  • 理想的索引应该具有下面几点:1: 查询频繁 2: 区分度高 3: 长度小 4: 尽量能覆盖常用查询字段。
  • 哪些列不应该建立索引呢?1、更新非常频繁的字段不适合建立索引。2、唯一性太差的字段不适合单独创建索引。3、不会出现在where子句中的字段不应该创建索引。
  • 索引覆盖: 索引覆盖是指 如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据. 这种查询速度非常快,称为”索引覆盖”
  • 不要用UUID或者随机字符串作为主键值,尽量用连续增长的值 对于innodb而言,因为节点下有数据文件,因此节点的分裂将会比较慢。对于innodb的主键,尽量用整型,而且是递增的整型。如果是无规律的数据,将会产生页的分裂,影响速度。关于UUID与自增主键的比较参看这篇文章

索引不是创建的越多越好。过多的索引不可能一次性读取到内存,索引是以索引文件的形式存储在磁盘上。过多的索引是会产生磁盘I/O消耗,从而影响性能。

特定语句优化

Count优化

MyIsam的count()比较快,原因是MyIsam对行数进行了存储。一旦有条件的查询, 速度就不再快了,尤其是where条件的列上没有索引。假如,id<100的商家都是我们内部测试的,我们想查查真实的商家有多少? select count(*) from lx_com where id>=100; (1000多万行用了6.X秒) 小技巧:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select count(*) from lx_com; 快
select count(*) from lx_com where id<100;

Join优化

Join语句经常听到“小结果集驱动大结果集”。为什么会有这句话?这和Mysql的关联查询原理有关。Mysql的关联查询是取第一张表的一行数据去遍历第二张表的所有数据找到匹配的行,依次遍历第一张表的数据。有人会问MN和NM结果不是一样的吗?“小结果集驱动大结果集”,这句话的前提是连接字段建立了索引。具体可以看下面的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT A.xx,B.yy 
FROM A INNER JOIN B USING(c)
WHERE A.xx IN (5,6)

上述代码的执行可以参照下面的伪代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
outer_iterator = SELECT A.xx,A.c FROM A WHERE A.xx IN (5,6);
outer_row = outer_iterator.next;
while(outer_row) {
    inner_iterator = SELECT B.yy FROM B WHERE B.c = outer_row.c;
    inner_row = inner_iterator.next;
    while(inner_row) {
        output[inner_row.yy,outer_row.xx];
        inner_row = inner_iterator.next;
    }
    outer_row = outer_iterator.next;
}

假设我们在A和B表的c列都建立了索引,可以看到外层循环无法用到索引一定会遍历M次,但是内层循环可以利用索引减少内存循环的次数,如果B的数据量大的话,优化效果还是非常可观的。

group by优化

Group by的实质是先排序然后分组。所以建议在group by中利用索引,这样可以减少临时表的创建以及文件排序。order by的列要和group by的一致,否则也会引起临时表 (原因是因为group by 和 order by 都需要排序,如果2者的列不一致,那必须经过至少1次排序)。以A,B表连接为例 ,主要查询A表的列, 那么 group by ,order by 的列尽量相同,而且列应该显示声明为A的列。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select A.id,A.cat_id from A inne join B group by A.cat_id order by A.cat_id

Limit优化

当表的数据非常多的时候,limit的分页优化可以用延迟索引。比如我们要查询5000000后的10条记录,用下面的语句效率是非常低的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select id,name from lx_com limit 5000000,10;

这是因为limit offset,N, 当offset非常大时, 效率极低, 可以先在子查询语句里利用覆盖索引扫描,然后再做一个关联查询,这种技术就是延迟索引 。SQL语句如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select id,name from lx_com inner join (select id from lx_com limit 5000000,10) as tmp using(id);

Union优化

建议使用union all 而不是union。union all 不过滤 效率提高,如非必须,请用union all。因为 union去重的代价非常高, Mysql会把各个查询结果插入到临时表中,然后做唯一性检查。所以请放在程序里去重。

性能分析工具

开启慢查询日志

MySQL 慢查询的相关参数解释:

slow_query_log :是否开启慢查询日志,1表示开启,0表示关闭。

log-slow-queries :旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log

slow-query-log-file:新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log

long_query_time :慢查询阈值,当查询时间多于设定的阈值时,记录日志。

使用profile语句

打开profile分析语句

查看分析列表

查看单条语句的执行过程

使用explain语句

如果要定量分析查询语句涉及到了多少行,可以使用explain。explain语句是非常重要的分析工具。提测之前使用explain分析一下SQL语句是一种美德。explain可以显示如下字段:

这里会选择比较重要几个字段的值通过列子进行讲解。

select_type 查询类型

  • simple语句中没有子查询或者union
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select field from table;
  • dependent subquery 子查询中的第一个select语句,依赖外部查询结果集
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from test.tabname where id in(select id from test.tabname2 where name='love');

以上语句有个错误的理解是认为按照下面两个结果执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select group_concat(id) from test.tabname2 where name='love';
--内层查询结果:1,3,5,7,9,11,13,15,17,1
 
select * from test.tabname where id in(1,3,5,7,9,11,13,15,17,19);

通过explain发现其实他是先根据关联外部tabname, 而不是先去执行这个子查询。可以通过连接查询来优化上面的语句。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select tabname. * from test.tabname inner join test.tabname2 using(id) where tabname2.name='love';

可以看到查询类型变成了simple简单查询。

  • primary最外层的select, 例子参见dependent subquery

type:很重要,显示了连接使用了哪种类别,有无使用索引。type代表查询执行计划(QEP)中指定的表使用的连接方式

从最好到最差依次为::system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL

  • system: const的一个特例,表中只有一条记录
  • const: where条件是以常量为单位,表中最多一条记录匹配。
  • eq_ref:最多只会有一条匹配结果,一般是通过主键或是唯一索引来访问。一般会出现在连接查询的语句中。通过索引列,直接引用某1行数据
  • ref: 它返回所有匹配某个单个值的行。它用在关联操作只使用了索引的最左前缀,或者索引不是UNIQUE和PRIMARY KEY。连接查询中被驱动的表索引引用查询.。通过索引列,可以直接引用到某些数据行
  • range: 引用范围扫描,见上面的例子
  • all: 全表扫描效率最低

possible key 可能用到哪些索引进行查询

key 实际用到的索引

key_len 实际用到的索引字节数 ref 列出是通过哪个字段来进行连接查询,或者是否是通过常量(const) extra 是EXPLAIN输出中另外一个很重要的列,该列显示MySQL在查询过程中的一些详细信息

重点关注下面几个值:

  • Using filesort:文件排序(文件可能在磁盘,也可能在内存)。需要注意的是,尽管名为 "filesort",但并不一定意味着排序操作会在磁盘文件中进行。如果排序的数据量小于 sort_buffer_size 和 read_rnd_buffer_size 参数设置的值,排序操作可以在内存中完成。只有当数据量太大,无法放入内存时,才会在磁盘上进行。
  • Using temporary:是指用上了临时表, group by 与order by 不同列时,或group by ,order by 别的表的列.
  • Using index:表示使用索引,如果只有 Using index,说明他没有查询到数据表,只用索引表就完成了这个查询,这个叫覆盖索引,效率非常高。
  • Using index condition:意味着MySQL 使用了“索引条件推送下”(Index Condition Pushdown,ICP)的优化策略。例如,假设我们有一个包含 id 和 name 两个列的表,id 列有一个索引。如果我们执行以下查询:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * FROM table WHERE id > 1000 AND name = 'John';

在这个例子中,id 列的条件可以直接使用索引,而 name 列的条件则不能。在没有 ICP 的情况下,MySQL 需要先从索引中找出所有 id > 1000 的行,然后对每一行检查 name 是否等于 'John'。而在使用 ICP 的情况下,MySQL 可以在检索索引时就过滤掉 name 不等于 'John' 的行,从而减少需要处理的数据量。

  • Using where:过滤元素的时候出现,也会扫描表,但是如果在条件语句中存在索引列,会优先使用带索引的条件。explain SELECT * from test where b = '4' (b不是索引,全表扫描后,通过过滤获取所需数据)

总结

本文先介绍了MySQL的架构,然后从数据类型、索引、性能分析三个角度描述如何进行数据库优化。相信当面试官再问你如何进行数据库优化的时候。你不会简单的回答“建索引”。最后提醒大家:提测前请explain

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-02-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java面试教程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MySQL优化原理
前言 说起MySQL的查询优化,相信大家收藏了一堆:不能使用SELECT *、不使用NULL字段、合理创建索引、为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原理? 在实际场景下性能真有提升吗?我想未必。因而理解这些优化建议背后的原理就尤为重要,希望本文能让你重新审视这些优化建议,并在实际业务场景下合理的运用。 一、MySQL逻辑架构    如果能在头脑中构建一幅MySQL各组件之间如何协同工作的架构图,有助于深入理解MySQL服务器。下图展示了MySQL的逻辑架构图。
用户1195962
2018/01/18
1.1K0
MySQL优化原理
【说站】mysql使用关联查询的注意点
在创建索引的时候就要考虑到关联的顺序。当表A和表B用列c关联的时候,如果优化器关联的顺序是A、B,那么就不需要在A表的对应列上创建索引。没有用到的索引会带来额外的负担,一般来说,除非有其他理由,只需要在关联顺序中的第二张表的相应列上创建索引。
很酷的站长
2022/11/23
1K0
MySql查询性能优化
在访问数据库时,应该只请求需要的行和列。请求多余的行和列会消耗MySql服务器的CPU和内存资源,并增加网络开销。 例如在处理分页时,应该使用LIMIT限制MySql只返回一页的数据,而不是向应用程序返回全部数据后,再由应用程序过滤不需要的行。 当一行数据被多次使用时可以考虑将数据行缓存起来,避免每次使用都要到MySql查询。 避免使用SELECT *这种方式进行查询,应该只返回需要的列。
lyb-geek
2018/07/26
2.2K0
数据库优化方案之SQL脚本优化
随着数据库数据越来越大,数据单表存在的数据量也就随之上去了,那么怎么样让我们的脚本查询数据更快呢?
用户1112962
2019/11/15
1.5K0
为什么 EXISTS(NOT EXIST) 与 JOIN(LEFT JOIN) 的性能会比 IN(NOT IN) 好
网络上有大量的资料提及将 IN 改成 JOIN 或者 exist,然后修改完成之后确实变快了,可是为什么会变快呢?IN、EXIST、JOIN 在 MySQL 中的实现逻辑如何理解呢?本文也是比较粗浅的做一些介绍,知道了 MySQL 的大概执行逻辑,也方便理解。本书绝大多数内容来自:高性能MySQL第三版(O'Reilly.High.Performance.MySQL.3rd.Edition.M),还有一部分来自于网络,还有的来自于自己的理解,以下的内容有引用的都会做标准,如有雷同,纯属巧合。
用户3148308
2018/10/10
6.9K0
mysql如何执行关联查询与优化
在数据库中执行查询(select)在我们工作中是非常常见的,工作中离不开CRUD,在执行查询(select)时,多表关联也非常常见,我们用的也比较多,那么mysql内部是如何执行关联查询的呢?它又做了哪些优化呢?今天我们就来揭开mysql关联查询的神秘面纱。
小忽悠
2018/09/04
3.5K0
mysql如何执行关联查询与优化
mysql的sql语句优化5种方式_MySQL数据库优化
本篇是MySQL知识体系总结系列的第二篇,该篇的主要内容是通过explain逐步分析sql,并通过修改sql语句与建立索引的方式对sql语句进行调优,也可以通过查看日志的方式,了解sql的执行情况,还介绍了MySQL数据库的行锁和表锁。
全栈程序员站长
2022/09/24
1.8K0
mysql的sql语句优化5种方式_MySQL数据库优化
深入探索SQL优化:利用慢查询日志和explain提升数据库效率
开始之前推荐一篇实用的文章:《MySQL存储引擎大厂面试经典三连问》,作者:【小白的大数据之旅】。
Lion 莱恩呀
2024/11/29
2600
深入探索SQL优化:利用慢查询日志和explain提升数据库效率
什么是内连接、外连接?MySQL支持哪些外连接?_oracle内连接和外连接的区别
图片与最后一部分来自:https://blog.csdn.net/plg17/article/details/78758593
全栈程序员站长
2022/09/27
1.2K0
什么是内连接、外连接?MySQL支持哪些外连接?_oracle内连接和外连接的区别
图解数据库内连接、外连接、左连接、右连接、全连接等
用两个表(a_table、b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接、外连接( 左(外)连接、右(外)连接、全(外)连接)。
浩Coding
2019/07/03
6.1K0
mysql执行计划看是否最优
  本篇主要通过汇总网上的大牛的知识,简单介绍一下如何使用mysql的执行计划,并根据执行计划判断如何优化和是否索引最优。
全栈程序员站长
2021/11/29
9060
mysql数据库优化(二)
https://www.cnblogs.com/sevck/p/6733702.html
用户1558882
2018/10/11
1.2K0
mysql数据库优化(二)
Mysql进阶优化篇01——四万字详解数据库性能分析工具(深入、全面、详细,收藏备用)
数据库的优化整个流程划分成了 观察(Show status) 和 行动(Action) 两个部分。数据库的优化可以总结为下图。字母 S 的部分代表观察(会使用相应的分析工具),字母 A 代表的部分是行动(对应分析可以采取的行动)。
半旧518
2022/10/26
1.1K0
Mysql进阶优化篇01——四万字详解数据库性能分析工具(深入、全面、详细,收藏备用)
MySQL优化必备之执行计划explain,索引基本知识,索引数据结构推演
这条SQL执行包含了PRIMARY、DEPENDENT SUBQUERY、DEPENDENT UNION和UNION RESULT
行百里er
2020/12/02
1.3K0
MySQL优化必备之执行计划explain,索引基本知识,索引数据结构推演
数据库优化 - SQL优化
前面一篇文章从实例的角度进行数据库优化,通过配置一些参数让数据库性能达到最优。但是一些“不好”的SQL也会导致数据库查询变慢,影响业务流程。本文从SQL角度进行数据库优化,提升SQL运行效率。
JAVA日知录
2019/11/06
1.8K0
数据库优化 - SQL优化
数据库:MySQL相关知识整理,值得收藏!
选择:MyISAM相对简单,所以在效率上要优于InnoDB。如果系统插入和查询操作多,不需要事务和外键,选择MyISAM,如果需要频繁的更新、删除操作,或者需要事务、外键、行级锁的时候,选择InnoDB。
小明互联网技术分享社区
2022/02/17
5200
数据库:MySQL相关知识整理,值得收藏!
MySql 全方位基础优化定位执行效率低的SQL语句存储过程与触发器的区别面试回答数据库优化问题从以下几个层面入手
SQL优化 通过show status命令了解各种sql的执行效率 查看本session的sql执行效率 show status like 'Com_%'; 查看全局的统计结果 SHOW GLOBAL STATUS LIKE 'Com_%' 查看服务器的状态 show global status; 结果 Com_select:执行select操作的次数,依次查询之累加1 Com_insert:执行insert操作的次数,对于批量插入的insert操作,只累加依次 Com_update:执行update操作
JavaEdge
2018/05/16
2.3K0
你真的了解MySQL了吗,那你给我说一下锁机制!
    这里显示的是明文密码通过哦MYSQLSHA1加密算法加密后得到的密文密码,是不可逆的,mysql 5.7 的密码保存到 authentication_string 字段中不再使用 password 字段。
上分如喝水
2021/08/16
6650
你真的了解MySQL了吗,那你给我说一下锁机制!
推荐阅读
相关推荐
MySQL优化原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验