(1)越小的数据类型一般更好:越小的数据类型一般在磁盘、内存和CPU缓存中都须要更少的空间,处理起来更快。
(2)简单的数据类型更好:整型数据比起字符,处理开销更小,由于字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。
(3)尽可能避免NULL:应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,由于它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。
(4)索引不会包含有NULL值的列。html
可是若是是一样的sql若是在以前可以使用到索引,那么如今使用不到索引,如下几种主要状况:mysql
1. 随着表的增加,where条件出来的数据太多,大于15%,使得索引失效(会致使CBO计算走索引花费大于走全表)sql
2. 统计信息失效 须要从新搜集统计信息数据库
3. 索引自己失效 须要重建索引缓存
下面是一些不会使用到索引的缘由
索引失效
1) 没有查询条件,或者查询条件没有创建索引;
2) 在查询条件上没有使用引导列
3) 查询的数量是大表的大部分,应该是30%以上。
4) 索引自己失效
5) 查询条件使用函数在索引列上(见12)
6) 对小表查询
7) 提示不使用索引
8) 统计数据不真实
9) CBO计算走索引花费过大的状况。其实也包含了上面的状况,这里指的是表占有的block要比索引小。
10)隐式转换致使索引失效.这一点应当引发重视.也是开发中常常会犯的错误. 因为表的字段tu_mdn定义为varchar2(20),
但在查询时把该字段做为number类型以where条件传给mysql,这样会致使索引失效.
错误的例子:select * from test where tu_mdn=13333333333;
正确的例子:select * from test where tu_mdn='13333333333';
11)对索引列进行运算致使索引失效,我所指的对索引列进行运算包括(+,-,*,/,! 等)
错误的例子:select * from test where id-1=9;
正确的例子:select * from test where id=10;
12)使用mysql内部函数致使索引失效.对于这样状况应当建立基于函数的索引.
错误的例子:select * from test where round(id)=10;
说明,此时id的索引已经不起做用了 正确的例子:首先创建函数索引,
create index test_id_fbi_idx on test(round(id));
而后 select * from test where round(id)=10; 这时函数索引发做用了bash
13)若是MySQL估计使用索引比全表扫描更慢,则不使用索引。例如若是列key_part1均匀分布在1到100之间,查询时使用索引就不是很好数据库设计
mysql>select * from table_name where key_part1>1 and key_part<90;
14)若是使用MEMORY/HEAP表而且where条件中不使用“=”进行索引列,那么不会用到索引。Heap表只有在“=”的条件下会使用索引。由于用的是哈希索引。函数
15)用or分割开的条件,若是or前的条件中的列有索引,然后面的列中没有索引,那么涉及的索引都不会被用到。mysql索引
mysql> show index from test1\G; *************************** 1. row *************************** Table: test1 Non_unique: 1 Key_name: inx_id_name Seq_in_index: 1 Column_name: name Collation: A Cardinality: 552589 Sub_part: NULL Packed: NULL Null: YES Index_type: BTREE Comment: Index_comment: *************************** 2. row *************************** Table: test1 Non_unique: 1 Key_name: inx_id_name Seq_in_index: 2 Column_name: id Collation: A Cardinality: 567855 Sub_part: NULL Packed: NULL Null: Index_type: BTREE Comment: Index_comment: 2 rows in set (0.00 sec) ERROR: No query specified mysql>
从上面能够发现只有name和id列上面有索引。来看以下的执行计划。
mysql> explain extended select * from test1 where name='name100' or dept='dept100'; +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | 1 | SIMPLE | test1 | NULL | ALL | inx_id_name | NULL | NULL | NULL | 769014 | 19.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 1 row in set, 2 warnings (0.00 sec) mysql>
16)若是将要使用的索引列不是复合索引列表中的第一部分,则不会使用索引
以下例子:可见虽然在id上面建有复合索引,可是因为id不是索引的第一列,那么在查询中这个索引也不会被MySQL采用。
mysql> explain select * from test1 where id=1; +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | 1 | SIMPLE | test1 | NULL | ALL | NULL | NULL | NULL | NULL | 787947 | 10.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql>
17)若是like是以%开始,可见虽然在name上面建有索引,可是因为where 条件中like的值的“%”在第一位了,那么MySQL也会采用这个索引。
若是WHERE子句的查询条件里使用了比较操做符LIKE和REGEXP,MYSQL只有在搜索模板的第一个字符不是通配符的状况下才能使用索引。好比说,若是查询条件是LIKE 'abc%',MYSQL将使用索引;若是条件是LIKE '%abc',MYSQL将不使用索引。
18)独立的列(对列变量须要计算(聚合运算、类型转换等))
独立的列是指索引列不能是表达式的一部分,也不是是函数的参数。例如如下两个查询没法使用索引:
1)表达式: select actor_id from sakila.actor where actor_id+1=5;
2)函数参数:select ... where TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col)<=10;应该把列计算转换成常量计算。
示例:
若是列类型是字符串,但在查询时把一个数值型常量赋值给了一个字符型的列名name,那么虽然在name列上有索引,可是也没有用到。
mysql> explain select * from company2 where name=294\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: company2 type: ALL possible_keys: ind_company2_name key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using where 1 row in set (0.00 sec)
而下面的sql语句就能够正确使用索引。
mysql> explain select * from company2 where name name=‘294'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: company2 type: ref possible_keys: ind_company2_name key: ind_company2_name key_len: 23 ref: const rows: 1 Extra: Using where 1 row in set (0.00 sec)
19).在JOIN操做中(须要从多个数据表提取数据时),MYSQL只有在主键和外键的数据类型相同时才能使用索引,不然即便创建了 索引也不会使用
20).在ORDER BY操做中,MYSQL只有在排序条件不是一个查询条件表达式的状况下才使用索引。尽管如此,在涉及多个数据表的查询里,即便有索引可用,那些索引在加快ORDER BY操做方面也没什么做用。
21).不要给“性别”增长索引。若是某个数据列里包含着许多重复的值,就算为它创建了索引也不会有很好的效果。好比说,若是某个数据列里包含了净是些诸如“0/1”或“Y/N”等值,就没有必要为它建立一个索引。
简单的说吧,不须要,由于性别,就两个值男与女(人妖不算,呵)。为这两个值创建索引是不值得的,由于不管多少条记录,创建性别的索引,最多让你的语句少检索一半。但与创建索引带来的损失比,捡芝麻丢西瓜。(可能不许确,但大意如些)。
打个比方,数据库就比如一本新华字典,咱们查数据时,能够根据拼音来查,字在字典的排序是根据拼音来排序的,咱们要查一个字,能够根据拼音很快就能查到咱们要查的字,这就叫做汇集索引!换句话说,汇集索引就是按照物理排序的,也由于是按物理排序的,因此一张表只能有一个汇集索引,也是最快的索引。固然,咱们也能够根据部首来查,可是这种查询必须先查找到部首,而后再到检索表查到那么字,最后才能查到咱们须要的字,你没办法像拼音查法同样翻翻字典就能够查到,这就叫做普通索引。普通索引能够有多个。
假如一本字典里全是"男"和"女"两个字,那么在检索表里也有不少个"男"和"女",这对查询帮助不大。
22).若是对大的文本进行搜索,使用全文索引而不使用like“%...%”.
23).若是列名是索引,使用column_name is null将使用索引。
以下
mysql> explain select * from company2 where name is null\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: company2 type: ref possible_keys: ind_company2_name key: ind_company2_name key_len: 11 ref: const rows: 1 Extra: Using where 1 row in set (0.00 sec)
24).不使用NOT IN和<>操做
NOT IN和<>操做都不会使用索引将进行全表扫描。NOT IN能够NOT EXISTS代替,id<>3则可以使用id>3 or id<3来代替。
25).排序的索引问题
mysql查询只使用一个索引,所以若是where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。所以数据库默认排序能够符合要求的状况下不要使用排序操做;尽可能不要包含多个列的排序,若是须要最好给这些列建立复合索引。
26).使用短索引
对串列进行索引,若是可能应该指定一个前缀长度。例如,若是有一个CHAR(255)的列,若是在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不只能够提升查询速度并且能够节省磁盘空间和I/O操做。
27).索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。因此咱们在数据库设计时不要让字段的默认值为NULL。
28).使用ENUM而不是字符串
ENUM保存的是TINYINT,别在枚举中搞一些“中国”“北京”“技术部”这样的字符串,字符串空间又大,效率又低。
若是索引正在工做,Handler_read_key的值将很高,这个值表明了一个行被索引值读的次数。
Handler_read_rnd_next的值高则意味着查询运行低效,而且应该创建索引补救。
mysql> show status like 'Handler_read%'; +-----------------------+--------+ | Variable_name | Value | +-----------------------+--------+ | Handler_read_first | 9 | | Handler_read_key | 16 | | Handler_read_last | 0 | | Handler_read_next | 680908 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 935519 | +-----------------------+--------+ 7 rows in set (0.00 sec) mysql>
分析表的语法以下:(检查一个或多个表是否有错误)
mysql> CHECK TABLE tbl_name[,tbl_name] …[option] …option = { QUICK | FAST | MEDIUM| EXTENDED | CHANGED} mysql> check table sales; +--------------+-------+----------+----------+ | Table | Op | Msg_type | Msg_text | +--------------+-------+----------+----------+ | sakila.sales | check | status | OK | +--------------+-------+----------+----------+ 1 row in set (0.01 sec)
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [,tbl_name]
若是已经删除了表的一大部分,或者若是已经对含有可变长度行的表进行了不少的改动,则须要作按期优化。这个命令能够将表中的空间碎片进行合并,可是此命令只对MyISAM、BDB和InnoDB表起做用。
mysql> optimize table sales; +--------------+----------+----------+----------+ | Table | Op | Msg_type | Msg_text | +--------------+----------+----------+----------+ | sakila.sales | optimize | status | OK | +--------------+----------+----------+----------+ 1 row in set (0.05 sec)