尽量不要让数据库做过多运算

数据库主要是用来存储的,我们应避免让数据库做运算,比如写定时任务,存储过程等。复杂的计算应该在程序代码中实现。我们应该尽量简单的使用数据库。

控制数据量

一年内单表数据量一般含char不超过500W条,我们需要合理的分表。单个库的表建议在300到400之间。

单表字段数量

单表的字段应该少而精,那多少合适呢?一般单表字段上线控制在20到50个。

在开发中,我们要注意避免使用大SQL、大事务。

避免使用NULL字段

我发现很多童鞋在建表时喜欢字段默认NULL,使用NULL很难进行查询优化,我们如果对NULL列加索引,需要额外空间,而且含NULL的符合索引无效。

`a` char(32) DEFAULT NULL
`b` int(10) NOT NULL

比如上面这种。

少用TEXT

我们可以使用VARCHAR代替TEXT,因为TEXT类型处理性能比VARCHAR要低,TEXT会强制生成临时表,从而浪费更多空间。UTF-8下,VARCHAR(65535)大概占用64K空间。

如果一定要使用,就拆成单独的一张表吧。

CREATE TABLE t1 (
    id INT NOT NULL AUTO_INCREMENT,
    data text NOT NULL,
    PRIMARY KEY (id)
ENGINE=InnoDB;

关于索引

索引数量建议

索引虽然能改善查询,但如果索引列更新频繁,索引维护也会成为负担。我们如果不加索引就尽量不要加,最好不要超过字段数的20%。

关于函数运算

不要在索引列进行数学运算或者函数运算,因为这样会使索引失效。

-- 不要这样用
select * from table WHERE to_days(current_date) – to_days(date_col) <= 10
-- 推荐使用
select * from table WHERE date_col >= DATE_SUB('2011-10-22',INTERVAL 10 DAY);

自增列做主键

自增列做主键,有利于索引维护,并且主键不应该平凡修改。别用字符串做主键,比如不要使用UUID做主键。

推荐用独立亍业务的AUTO_INCREMENT列或全局ID生成器做代理主键。

我们知道,InnoDB中,主键索引默认是以主键列创建的,那么问题来了。

如果没有指定主键,那么还会创建主键索引么?

尽量少使用外键

如果使用了外键,高并发下面容易产生死锁。我们应该由程序来保证约束。

SQL语句要简单

我看过好几百行的SQL,我认为这样不太好,一般一条SQL只能在一个CPU中运算,一条大SQL可能把数据库搞崩。

我们应该将大SQL拆成多条简单的小SQL,简单的SQL会使缓存命中率更高。

关于事务

我们应该尽量将与事务无关的操作放到事务外面,这样能减少锁资源的占用。

简单的使用

我们尽量少使用存储过程,触发器,尽量少用MySQL函数处理结果。数据的运算应该交由程序去操作。

关于SQL效率

改写OR为IN()

同一字段,将or改写为in()

  • OR效率:O(n)
  • IN 效率:O(Log n)
  • 当n很大时,OR会慢很多
Select * from table WHERE phone='12347856' or phone='42242233';

-- 推荐使用in
Select * from table WHERE phone in ('12347856' , '42242233')

不同字段,将or改为union

Select * from table WHERE phone='010-88886666' or cellPhone='13800138000';

-- 推荐使用 union
Select * from table WHERE phone='010-88886666'
union
Select * from table WHERE cellPhone='13800138000';

用UNION ALL 而非 UNION

使用UNION会有去重开销。

关于JOIN

很多童鞋喜欢使用JOIN来连表查询,阿里巴巴开发手册里就建议不要超过三表的JOIN。

建议将表拆分。

Select * from tag JOIN tag_post on tag_post.tag_id=tag.id JOIN post on  tag_post.post_id=post.id WHERE tag.tag='二手玩具';

推荐这样做:

Select * from tag WHERE tag='二手玩具';
Select * from tag_post WHERE tag_id=1321;
Select * from post WHERE post.id in (123,456,314,141)

关于计数统计

  • 实时统计:用memcache,双向更新,凌晨跑基准
  • 非实时统计:尽量用单独统计表,定期重算

关于limit分页

我们平常可能写过这样的SQL:

Select * from table limit 10000,10;

但是这样会很慢,偏移量越大越慢。

我们推荐使用这样的方式

select * from table WHERE id>=23434 limit 11;

网上有人做了测试:

不要在程序端对数据库显示加锁

  • 外部锁对数据库不可控
  • 高并发时是灾难
  • 极难调试和排查


©著作权归作者所有:来自51CTO博客作者mob604756ed27a0的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. MYSQL存储引擎与SQL性能下降原因
  2. 第五章 主生产计划MPS 第4~5节 MPS计划生成、MPS运算结果
  3. 【MySQL】如何对SQL语句进行跟踪(trace)?
  4. 使用位图连接索引优化OLAP查询
  5. 【DB笔试面试561】在Oracle中,如何预估即将创建索引的大小?
  6. Oracle之函数索引
  7. Python中tuple和list有什么区别?Python入门!
  8. Hadoop下水环境模拟集群运算模式
  9. 单芯片每秒1000万亿次运算:谷歌TPU原班团队全新AI架构,晶体管性能

随机推荐

  1. php中的date函数中时区问题
  2. 基于PHP会话的登录系统出现问题
  3. PHP - 在外部服务器上读取文件?
  4. php 获取当前页面url路径
  5. log4php将不同级别的日志打印到不同的日
  6. 注意:未定义的变量:after_widget in ... wp
  7. php 23种设计模型 - 抽象工厂模式
  8. 巧用PHP中__get()魔术方法
  9. PHP程序员的技术成长规划(转)
  10. php时间函数——获取过去24小时内每个小