因为之前迭代版本,很多优化工作拖到了现在。主要先做慢查询的优化。 先就索引这块,做个大概的说明。如何建索引,索引何时会在sql中用上。
索引相关
大多数MySQL索引(PRIMARY KEY、UNIQUE、INDEX和FULLTEXT)在B树中存储。只是空间列类型的索引使用R-树,并且MEMORY表还支持hash索引。
不能使用索引
索引是消耗物理空间从而加快查询效率,所以索引并非越多越好。数据的增删改都需要维护索引,数据量小的表建索引也是毫无意义的。 而且,索引也并非是所有的查询都可以用上,如<>,not in ,!=以及%–%,%–(–%是可以用到索引的)都不会用到索引,另外的一些操作符 <,<=,=,>,>=,BETWEEN,IN等等都是可以用到索引的。下面还额外列出了不能使用索引的场景: 1.对列进行函数运算的情况(如 where md5(password) = “xxxx”) 2.WHERE index=1 OR A=10 3.存了数值的字符串类型字段(如手机号),查询时记得不要丢掉值的引号,否则无法用到该字段相关索引,反之则没关系 select * from test where mobile = 17611111111; 是无法用到mobile字段的索引的(如果mobile是char 或 varchar类型的话)
什么样的字段不适合建索引
1.一般来说,列的值唯一性太小(如性别,类型什么的),不适合建索引(怎样叫太小?一半说来,同值的数据超过表的百分之15,那就没必要建索引了) 2.太长的列,可以选择只建立部分索引,(如:只取前十位做索引) 3.更新非常频繁的数据不适宜建索引
联合索引使用
由于一次查询只能用到一个索引,所以在必要的情况下,可以建联合索引,是ab索引还是ba索引,区分度高者在前。 但是联合索引的一个问题是,联合索引的后者不能单独拿出来做索引。如where a=xxx,a是可以做索引的,但是where b=xxx,b索引是没有用的。 所以大多数情况下,有ab索引了,就没有必要再去单独建一个a索引。
覆盖索引拥有更高效率
如果select出来的字段都加了索引的话,查询效率更高
null会导致索引形同虚设
在设计表结构的时候要避免null的存在
mysql innodb上select count(*)的性能问题
常用的mysql引擎有两个,一个是innodb,还有一个myisam。 MyISAM引擎表不支持事务,读写操作会相互冲突,仅支持表级别锁。当其上的查询或者写入操作时间比较长的时候,会阻塞其他操作,容易导致连接堆积,而且在crash 后存在数据丢失的风险。 除此之外这两个引擎还有一个很大的不同点,myisam内部有个计数器,会自动保存表的总行数,读取总数只要简单的读出保存好的行数即可。但是innodb在获取总行数的时候需要全表扫描,这是 一个相当耗性能的操作。
关于innodb引擎的一些优化建议:
1、每个字段的长度控制在768字节以内 原因:当Innodb的存储格式是 ROW_FORMAT=COMPACT (or ROW_FORMAT=REDUNDANT)的时候, Innodb只会存储前768字节的长度,剩余的数据存放到“溢出页”中。 一旦采用了这种“溢出存储”,返回数据的时候本来是顺序读取的数据,就变成了随机读取了,会导致性能急剧下降。 并且Innodb并没有将溢出页(overflow page)缓存到内存里面。
2、InnoDB 中不保存表的具体行数,也就是说,执行select count() from table时, InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含 where条件时,两种表的操作有些不同,InnoDB类型的表用count(*)或者count(主键),加上where col 条件。其中col列是表的主键之外的其他具有唯一约束索引的列。这样查询时速度会很快,就是可以避免全表扫描。
3、对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引, 但是在MyISAM表中,可以和其他字段一起建立联合索引。
4、DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5、LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表, 导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
6、innodb要熟练使用覆盖索引技术(建立合适的联合索引)
select a from table_name where b 这样的一个查询,都知道索引应该加在b上面, 查询的处理过程:首先去检索b索引找到与其对应的索引,然后根据索引去检索正确的数据行。 这样一来一去就是两次检索,能不能通过一次检索而得到数据呢? 如果希望通过一次检索得到数据,那么索引上面就应该包含其索引相对的数据,这样可能吗? alter table_name add index (b,a); 添加一个这样的索引就能实现了, 查看是否使用了覆盖索引; 使用 explain select …如果 extra: use index 就表示使用了覆盖索引。