娱乐

mysql优化的几种方法

时间:2010-12-5 17:23:32  作者:知识   来源:时尚  查看:  评论:0
内容摘要:我接手过一个线上商城项目,数据库里订单表才三百万行,每次按用户查订单要等两秒多。后来发现罪魁祸首是SELECT *把二十多个字段全捞出来,而页面只显示其中五个。改成只查需要的列后,响应时间直接掉到四百

我接手过一个线上商城项目,种方数据库里订单表才三百万行,种方每次按用户查订单要等两秒多。种方后来发现罪魁祸首是种方SELECT *把二十多个字段全捞出来,而页面只显示其中五个。种方改成只查需要的种方列后,响应时间直接掉到四百毫秒。种方这是种方最廉价也最容易被忽略的优化——查询时少碰数据。

索引是种方另一个重头戏。那个项目的种方订单表上有个联合索引(user_id, status),但开发人员写查询时用了WHERE status = 'paid' AND user_id = 123,种方顺序反了,种方索引直接失效。种方MySQL的种方索引最左前缀原则不是开玩笑的——你调整一下字段顺序,执行计划从ALL全表扫描变成ref,种方速度提升十倍不止。但别急着给所有列都加索引,写入频繁的表会因此付出代价,每次插入都要更新索引树。我见过有人给布尔字段加索引,纯粹浪费空间。

说到EXPLAIN,我几乎每次调优都先看它。有一次发现某条查询的type列是index,意味着MySQL在扫全索引。那是个状态字段,区分度极低——只有“成功”和“失败”两种值,索引扫描了一半数据。后来我改成WHERE created_at > 某个时间点 AND status = 'success',让时间字段走索引先过滤,效果立竿见影。低区分度字段单独建索引是自欺欺人,配合其他高区分度字段才有意义。

分页查询是另一个坑。项目里有个后台列表要按时间倒序翻页,越往后翻越慢,因为LIMIT 200000, 20要扫描前二十万行再丢弃。我把方案改成记住上一页最后一条记录的ID,用WHERE id < 上一页最小ID ORDER BY id DESC LIMIT 20,翻到十万页也毫秒级响应。这种延迟关联的思路同样适用于大表——先通过覆盖索引找出主键,再回表取完整行,比直接全行扫描快得多。

表结构设计上,我吃过亏。原表有个VARCHAR(255)的字段存用户备注,实际平均长度才十几个字符。MySQL的VARCHAR虽然变长,但排序时按最大长度分配内存,导致ORDER BY这个字段时临时表膨胀。后来改成VARCHAR(50),排序快了不少。类似的还有用TEXT类型存储短内容——完全没必要,TEXT在磁盘上单独存储,查询时要多一次IO。

慢查询日志不能只开着不管。我把阈值设为一秒,每周扫一次日志,把高频慢查询拎出来单独处理。有一次发现某个统计接口每天凌晨被定时任务跑几百次,每次全表扫描——后来改成定时汇总到统计表,接口直接查结果,压力瞬间消失。缓存不是银弹,但把热点数据扔进Redis或MySQL的查询缓存(如果版本支持),能挡住百分之八十的重复请求。

最后一招是分库分表,但这是最后的手段。三百万行就分表,纯属过度设计。真到千万级,先试试归档旧数据——把三年前的历史订单挪到冷表,热表缩小到百万行内,大部分问题迎刃而解。MySQL优化不是堆技巧,而是先定位瓶颈在IO、CPU还是锁竞争,然后对症下药。别迷信某个单一方案能解决所有问题,每个系统都有自己的脾气。

最近更新
热门排行
copyright © 2026 powered by 力不从心网   sitemap