# MySQL优化基本操作 https://learnku.com/articles/60619 https://learnku.com/articles/61064 ## 優化注意事項 https://juejin.cn/post/7208571916154847288 ## where 及 order by 涉及的列上建立索引 ## limit https://www.bilibili.com/video/BV1Kr4y1i7ru?p=93&spm_id_from=pageDriver&vd_source=f726dd30598fe01d9fbc9c5a988d6408 也可以用where https://segmentfault.com/a/1190000021287858 如果您的需求是簡單的分頁,則使用 WHERE 和 LIMIT 的方法通常更適合。如果您需要更多靈活性和複雜性,則可以考慮使用自連接表的方法 ## 尽可能不要使用 NULL 值 因为建表的时候,如果不对创建的值设置默认值,MySQL 都会设置默认为 NULL。那么为啥用 NULL 不好呢? * NULL 使得索引维护更加复杂,强烈建议对索引列设置 NOT NULL * NOT IN、!= 等负向条件查询在有 NULL 值的情况下返回永远为空结果,查询容易出错 * NULL 列需要一个额外字节作为判断是否为 NULL 的标志位 * 使用 NULL 时和该列其他的值可能不是同种类型,导致问题。(在不同的语言中表现不一样) * MySQL 难以优化对可为 NULL 的列的查询 所以对于那些以前偷懒的字段,手动设置一个默认值吧,空字符串呀,0 呀补上。 虽然这种方法对于 MySQL 的性能来说没有提升多少,但是这是一个好习惯,而且以小见大,不要忽略这些细节。 查詢注意欄位 如果是不等於 記得她不會找null 的 所以要 or  ## 添加索引 对于经常查询的字段,请加上索引,有索引和没有索引的查询速度相差十倍甚至更多。 * 一般来说,每张表都需要有一个主键 id 字段 * 常用于查询的字段应该设置索引 * varchar 类型的字段,在建立索引的时候,最好指定长度 * 查询有多个条件时,优先使用具有索引的条件 * 像 LIKE 条件这样的模糊搜索对于字段索引是无效的,需要另外建立关键词索引来解决 **请尽量不要在数据库层面约束表和表之间的关系**,这些表之间的依赖应该在代码层面去解决 当表和表之间有约束时,虽然增删查的 SQL 语句变简单了,但是带来的负面效果是插入等操作数据库都会去检查约束(虽然可以手动设置忽略约束),这样相当于把一些业务逻辑写到了数据库层,不便于维护。 ## 数据库中那些可以用整形表示的数据就不要使用字符串类型,到底是用 varchar 还是 char 要看字段的可能值。 这种优化往往在数据库中有大量数据以后是不可行的,最好在数据库设计之前就设计好。 * 对于那些可能值很有限的列,使用 tinyint 代替 VARCHAR, * 比如记录移动设备平台,只有两个值:android,ios,那么就可以使用 0 表示 android,1 表示 ios,这种列一定要写好注释 * 为什么不用 ENUM 呢?ENUM 扩展困难,比如后来移动平台又增加了一个 ipad,那岂不是懵逼了,而 tinyint 加个 2 就行,而且 ENUM 在代码里面处理起来特别奇怪,是当成整形呢还是字符串,各个语言不一样。 * 这种方式,一定要在数据库注释或者代码里面写明各个值的含义 * 对于那些定长字符串,可以使用 char,比如邮编,总是 5 位 * 对于那些长度未知的字符串,使用 varchar * 不要滥用 bigint,比如记录文章数目的表 id 字段,用 int 就行了,21 亿篇文章上限够了 * 适当打破数据库范式添加冗余字段,避免查询时的表连接 查询的时候,肯定 int 类型比 varchar 快,因为整数的比较直接调用底层运算器就可以实现,而字符串比较要逐个字符比较。 定长数据比变长数据查询快,因为比较定长数据与数据之间的偏移是固定的,很容易计算下一个数据的偏移。而变长数据则还需要多一步去查询下一个数据的偏移量。不过。定长数据可能会浪费更多的存储空间 ## 大表拆分 对于那些数据量可能近期会超过 500W 或者增长很快的表,一定要提前做好垂直分表或者水平分表,当数据量超过百万以后,查询速度会明显下降。 分库分表尽量在数据库设计初期敲定方案,否则后期会极大增加代码复杂性而且不易更改。 垂直分表是按照日期等外部变量进行分表,水平分表是按照表中的某些字段关系,使用 hash 映射等分表。 分库分表的前提条件是在执行查询语句之前,已经知道需要查询的数据可能会落在哪一个分库和哪一个分表中。 ## 优化查询语句 这个才是很多系统数据库瓶颈的始作俑者。 * 请尽量使用简单的查询,避免使用表链接 * 请尽量避免全表扫描,会造成全表扫描的语句包括但不限于: * where 子句条件恒真或为空 * 使用 LIKE * 使用不等操作符(<>、!=) * 查询含有 is null 的列 * 在非索引列上使用 or * 多条件查询时,请把简单查询条件或者索引列查询置于前面 * 请尽量指定需要查询的列,不要偷懒使用 select * * 如果不指定,一方面会返回多余的数据,占用带宽等 * 另一方面 MySQL 执行查询的时候,没有字段时会先去查询表结构有哪些字段 * 大写的查询关键字比小写快一点点 * 使用子查询会创建临时表,会比链接(JOIN)和联合(UNION)稍慢 * 在索引字段上查询尽量不要使用数据库函数,不便于缓存查询结果 * 当只要一行数据时,请使用 LIMIT 1,如果数据过多,请适当设定 LIMIT,分页查询 * 千万不要 ORDER BY RAND (),性能极低 隐式类型转换,会导致索引失效,例如 age 字段类型是 int,我们 where age = “1”,这样就会触发隐式类型转换。 ## 日常工作中你是怎么优化 SQL 的 可以从这几个维度回答这个问题: * 加索引 * 避免返回不必要的数据 * 适当分批量进行 * 优化 sql 结构 * 主从架构,提升读性能 * 分库分表 ## 数据库索引的原理,为什么要用 B + 树,为什么不用二叉树? 可以从几个维度去看这个问题,查询是否够快,效率是否稳定,存储数据多少,以及查找磁盘次数,为什么不是二叉树,为什么不是平衡二叉树,为什么不是 B 树,而偏偏是 B + 树呢? ## 为什么不是一般二叉树? 1)当数据量大时,树的高度会比较高(树的高度决定着它的 IO 操作次数,IO 操作耗时大),查询会比较慢。 2)每个磁盘块(节点 / 页)保存的数据太小(IO 本来是耗时操作,每次 IO 只能读取到一个关键字,显然不合适),没有很好的利用操作磁盘 IO 的数据交换特性,也没有利用好磁盘 IO 的预读能力(空间局部性原理),从而带来频繁的 IO 操作。 ## 为什么不是平衡二叉树呢? 我们知道,在内存比在磁盘的数据,查询效率快得多。如果树这种数据结构作为索引,那我们每查找一次数据就需要从磁盘中读取一个节点,也就是我们说的一个磁盘块,但是平衡二叉树可是每个节点只存储一个键值和数据的,如果是 B 树,可以存储更多的节点数据,树的高度也会降低,因此读取磁盘的次数就降下来啦,查询效率就快啦。 ## 那为什么不是 B 树而是 B + 树呢? 1)B+Tree 范围查找,定位 min 与 max 之后,中间叶子节点,就是结果集,不用中序回溯 2)B+Tree 磁盘读写能力更强(叶子节点不保存真实数据,因此一个磁盘块能保存的关键字更多,因此每次加载的关键字越多) 3)B+ ## . 如何选择合适的分布式主键方案呢? * 数据库自增长序列或字段。 * UUID * 雪花算法 * Redis 生成 ID * 利用 zookeeper 生成唯一 ID ###### tags: `MySql`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up