当前位置:首页 > 问答 > 正文

数据库管理和维护那些事儿,聊聊SQL里头不太好说的技巧和经验

某资深DBA技术博客“老鸟的菜园子”、《SQL解惑(第2版)》部分案例、以及技术社区“CSDN”多位用户的经验分享整合)

直接开聊,干数据库这行,有些东西手册上不写,培训班不讲,都是平时一点点抠出来的经验,今天说的这些,算不上多高深,但能让你少加不少班。

*关于COUNT()的误会**

很多人觉得COUNT(1)比COUNT(*)快,COUNT(列名)又比COUNT(1)快,其实在绝大多数现代数据库(比如MySQL、PostgreSQL)里,*COUNT()是最优的*。(来源:MySQL官方性能优化文档)数据库引擎对COUNT()做了很多优化,它会自动找最快的索引来统计行数,你非要写COUNT(1)或者COUNT(主键),数据库还得去多判断一下1是不是NULL,或者主键是不是NULL(主键当然不是NULL,但这步判断省不了),反而绕了点路,COUNT(列名)就更别说了,它要跳过该列为NULL的行,效率更低,下次想知道表里有多少条记录,放心大胆地用COUNT(*),别想太多。

UPDATE的时候,小心“顺带手”的全表扫描

你可能会写这样的语句:UPDATE users SET status = 1 WHERE name = '张三',看起来没问题对吧?但如果name字段上没有索引,这个UPDATE就会引发一次全表扫描,这还不是最可怕的,可怕的是,在UPDATE的过程中,数据库通常会对涉及的行加锁(取决于事务隔离级别),如果表很大,这个锁可能会持有很长时间,导致其他想读写这张表的请求全部排队等着,网站可能就“卡死”了。(来源:CSDN用户“数据库踩坑王”的血泪教训)执行UPDATE或DELETE前,最好先 EXPLAIN 一下你的WHERE条件,看看它有没有用上合适的索引,别让一个点修改成了整个数据库的性能瓶颈。

索引不是越多越好,它像盐,多了齁咸

看见查询慢,第一反应就是“加个索引”?打住,每个索引都是一棵“小树”(B+树),每次你INSERT、UPDATE、DELETE数据时,数据库不仅要动主数据,还要去更新所有相关的“小树”,索引越多,写操作的成本就越高,磁盘空间占用也越大。(来源:《高性能MySQL(第3版)》)我曾经见过一张表上建了十几个索引,导致插入速度慢得像蜗牛。一个好的法则是:一张表的索引数量最好不要超过5个,优先考虑复合索引(多个字段组成的索引),并且把最常用于查询条件的字段放在前面,比如你经常用where a=1 and b=2,那建一个(a, b)的复合索引就比单独建(a)和(b)两个索引要高效得多。

搞不清JOIN和EXISTS,瞎用一气

有时候你需要判断“是否存在”,找所有下过订单的用户,菜鸟可能会这么写: SELECT DISTINCT u.* FROM users u JOIN orders o ON u.id = o.user_id 用DISTINCT来去重,如果用户订单很多,这个去重操作开销很大。

老手会用EXISTS: SELECT * FROM users u WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id) (来源:《SQL解惑(第2版)》谜题21)EXISTS只要在子查询里找到一条匹配的记录就立刻返回True,像个短路操作,效率高很多,反过来,当你需要从多个表获取数据时,JOIN通常是更好的选择。核心区别是:需要对方表的详细数据时用JOIN,只关心“是否存在”时用EXISTS。

维护的“玄学”:定期“整理”一下表

数据库用久了,就像电脑硬盘会产生碎片一样,数据和索引也会变得零散,删除数据后,那些空间可能不会立刻回收,新的数据又见缝插针,导致查询效率下降,这时候就需要做一些维护操作。

  • 对于MySQL的InnoDB表:定期执行OPTIMIZE TABLE 表名,这相当于一次“磁盘整理”,会重建表并优化索引,释放空间,不过这个操作会锁表,一定要在业务低峰期做。
  • 对于PostgreSQL:有类似的VACUUM FULL命令,作用差不多。(来源:PostgreSQL官方维护文档) 这个活不用天天干,但一两个月做一次,对保持数据库的“健康”很有好处,很多人只知道备份,忽略了这种“健身”操作,等数据库慢到不行了才想起来找原因。

最后聊个心态问题:别怕执行计划(EXPLAIN)

那个输出结果看起来一堆术语,什么type、key、rows、Extra,刚开始看确实头大,但你不用全懂,就盯住几个关键点:(来源:多位社区专家的共同建议)

  1. type列:如果出现了“ALL”,就意味着全表扫描,这是警报!想办法让它用上索引,变成“ref”或“range”。
  2. key列:看看它实际使用了哪个索引,是不是你期望的那个。
  3. Extra列:如果出现“Using filesort”或“Using temporary”,说明数据库在吃力地进行排序或创建临时表,对于大数据集这也是性能杀手。

多看几次,慢慢就懂了,这东西是排查慢查询最直接的武器。

数据库管理和维护,三分靠技术,七分靠细心和经验,多动手,多踩坑,慢慢就成老司机了。

数据库管理和维护那些事儿,聊聊SQL里头不太好说的技巧和经验