mysql 数据库库优化之 小结

 

一,sql语句的优化

1,任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

2,对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

3,应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: 
      select id from t where num is null 
     可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: 
     select id from t where num=0

4,应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: 
      select id from t where num=10 or num=20 
     可以这样查询: 
     select id from t where num=10 
     union all 
     select id from t where num=20

5,并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。或者查询结果占全表的20%以上时,也不会利用索引。

6,索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。

7,mySQL数据库Sql语句执行效率检查--Explain命令

       Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。

Explain语法:explain select … from … [where ...]

例如:explain select * from news;

输出:

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+

最关键的是possible_keys:列指出MySQL能使用哪个索引。

key:显示MySQL实际使用的键(索引)。如果没有选择索引,键是NULL

二,了解一下存储引擎

1,概念

       关系数据库表是用于存储和组织信息的数据结构,可以将表理解为由行和列组成的表格,类似于Excel的电子表格的形式。有的表简单,有的表复杂,有的表根本不用来存储任何长期的数据,有的表读取时非常快,但是插入数据时去很差;而我们在实际开发过程中,就可能需要各种各样的表,不同的表,就意味着存储不同类型的数据,数据的处理上也会存在着差异,那么。对于MySQL来说,它提供了很多种类型的存储引擎,我们可以根据对数据处理的需求,选择不同的存储引擎,从而最大限度的利用MySQL强大的功能。这篇博文将总结和分析各个引擎的特点,以及适用场合,并不会纠结于更深层次的东西。我的学习方法是先学会用,懂得怎么用,再去知道到底是如何能用的。下面就对MySQL常见的存储引擎进行简单的介绍。

2,常见存储引擎

MyISAM

在mysql客户端中,使用以下命令可以查看MySQL支持的引擎。

代码如下:
show engines;

MyISAM表是独立于操作系统的,这说明可以轻松地将其从Windows服务器移植到Linux服务器;每当我们建立一个MyISAM引擎的表时,就会在本地磁盘上建立三个文件,文件名就是表明。例如,我建立了一个MyISAM引擎的tb_Demo表,那么就会生成以下三个文件:

1.tb_demo.frm,存储表定义;
2.tb_demo.MYD,存储数据;
3.tb_demo.MYI,存储索引。

MyISAM表无法处理事务,这就意味着有事务处理需求的表,不能使用MyISAM存储引擎。MyISAM存储引擎特别适合在以下几种情况下使用:

1.选择密集型的表。MyISAM存储引擎在筛选大量数据时非常迅速,这是它最突出的优点。
2.插入密集型的表。MyISAM的并发插入特性允许同时选择和插入数据。例如:MyISAM存储引擎很适合管理邮件或Web服务器日志数据。

InnoDB

InnoDB是一个健壮的事务型存储引擎,这种存储引擎已经被很多互联网公司使用,为用户操作非常大的数据存储提供了一个强大的解决方案。我的电脑上安装的MySQL 5.6.13版,InnoDB就是作为默认的存储引擎。InnoDB还引入了行级锁定和外键约束,在以下场合下,使用InnoDB是最理想的选择:

1.更新密集的表。InnoDB存储引擎特别适合处理多重并发的更新请求。
2.事务。InnoDB存储引擎是支持事务的标准MySQL存储引擎。
3.自动灾难恢复。与其它存储引擎不同,InnoDB表能够自动从灾难中恢复。
4.外键约束。MySQL支持外键的存储引擎只有InnoDB。

一般来说,如果需要事务支持,并且有较高的并发读取频率,InnoDB是不错的选择。

三,索引

        官方介绍索引是帮助MySQL高效获取数据的数据结构。我的理解索引相当于一本书的目录,通过目录就知道要的资料在哪里,不用一页一页查阅找出需要的资料。关键字index。

索引的分类

1、主键索引

可以在建立表的添加 

CREATE TABLE `class` (
  `id` int(11) NOT NULL DEFAULT '0',
  `classname` varchar(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `classname` (`classname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

可以在建立完表之后,添加:alter table tablename add primary key(列1,列2)

例如:ALTER TABLE class ADD PRIMARY KEY (id)

主键索引的特点:

(1)一个表中最多只有一个主键索引

(2)一个主键索引可以指向多个列

(3)主键索引的列,不能有重复的值,也不能有null

(4)主键索引的效率高。

2、唯一索引

可以在建立表的时候添加:create table emp(name varchar(32) unique)

在建完表之后,添加:

alter table tablename add unique  key  [索引名](列名)

例如:ALTER TABLE class ADD UNIQUE KEY (classname)

唯一索引的特点:

(1)一个表中可以有多个唯一索引

(2)一个唯一索引可以指向多个列 ,

比如alter table  tablename add unique [索引名](列1,列2)

(3)如果在唯一索引上,没有指定not null,则该列可以为空,同时可以有多个null,

(4)唯一索引的效率较高。

 3、普通索引

使用普通索引主要是提高查询效率

 添加alter table tablename add index [索引名](列1,列3)

 \

4、全文索引

mysql自带的全文索引mysql5.5不支持中文,支持英文,同时要求表的存储引擎是myisam,InnoDB不支持,。如果希望支持中文,有两个方案,

(1)使用aphinx中文版coreseek (来替代全文索引)

(2)插件mysqlcft。

5、查看索引

(1)show index from 表名

(2)show indexes from 表名

(3)show keys from 表名

(4)desc 表名

6、删除索引

(1)主键索引的删除:

alter table tablename drop primary key;要注意:在删除主键索引时,要首先去掉auto_increment属性。

(2)唯一索引的删除

alter table tablename drop index 唯一索引的名字

 (3)普通索引的删除:

alter table tablename drop index 普通索引的名字

四,索引的使用

1,最左前缀原则

对于创建的多列(复合)索引,只要查询条件使用了最左边的列,索引一般就会被使用,反之没有使用最左边的列,将不会使用索引。

2,对于使用like的查询,查询如果是”%XXX”,不会使用到索引,‘XXX%’会使用到索引。

3、如果条件中有or,则要求or的索引字段都必须有索引,否则不能用到索引。

\

该email添加索引后,在测试,会用到索引

\

4、如果列类型是字符串,一定要在条件中将数据使用引号引用起来,否则不使用索引。

\


5、优化group by语句

默认情况下, mysql对所有的group by col1,col2进行排序。这与在查询中指定order by col1,col2类型,如果查询中包括group by 但用户想要避免排序结果的消耗,则可以使用order by null禁止排序。

\

6、当取出的数据量超过表中数据的20%,优化器就不会使用索引,而是全表扫描。扫描的行数太多了,优化器认为全表扫描比索引来的块。

7、对应大批量插入数据

对于MyISAM:

             先禁用索引:

             alter table table_name disable keys;

loading data//insert语句; 执行插入语句

执行完成插入语句后,开启索引,统一添加索引。

alter table table_name enable keys;

对于Innodb:

1,将要导入的数据按照主键排序

2,setunique_checks=0,关闭唯一性校验。

3,setautocommit=0,关闭自动提交。

五,分区

就是把一个表存储到磁盘不同区域,仍然是一张表。

1、基本的概念:

mysql5.1后有4种分区类型:

(1)Range(范围)–这种模式允许将数据划分不同范围。例如可以将一个表通过年份划分成若干个分区。

(2)List(预定义列表)–这种模式允许系统通过预定义的列表的值来对数据进行分割

(3)Hash(哈希)–这中模式允许通过对表的一个或多个列的Hash Key进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区。例如可以建立一个对表主键进行分区的表。

(4)Key(键值)-上面Hash模式的一种延伸,这里的Hash Key是MySQL系统产生的。

2 range分区:

假如你创建了一个如下的表,该表保存有20家超市的职员记录,这20家超市的编号从1到20.如果你想将其分成4个小分区,可以采用range分区,创建的数据表如下。

创建range分区语法:

  1. create table emp(
  2. id int not null,
  3. namevarchar( 32) not null default '' comment ‘职员的名称’,
  4. store_id int not null comment ‘超市的编号范围是 1 -20
  5. ) engine myisam charset utf8
  6. partition by range(store_id)(
  7. partition p0 values less than( 6), //是store_id的值小于 6的存储区域。
  8. partition p1 values less than( 11), //是store_id的值大于等于 6小于 11的存储区域。
  9. partition p2 values less than( 16),
  10. partition p3 values less than( 21)
  11. )
  12. insert into emp values( 1,’哈哈’, 1) --à数据是存储到p0区
  13. insert into emp values( 23,’呵呵呵’, 15) --à数据是存储到p2区
  14. insert into emp values( 100,’嘻嘻嘻’, 11)=à数据是存储到p2区。

测试使用取出数据时是否用到分区: 

\

在取出数据时,条件中必须partitionby range(store_id),range里面的字段。

3、list分区与range分区有类似的地方

例子:假如你创建一个如下的一个表,该表保存有20家超市的职员记录,这20家超市的编号从1到20.而这20家超市分布在4个有经销权的地区,如下表所示:

  1. create table emp(
  2. id int not null,
  3. name varchar( 32) not null default '',
  4. store_id int not null
  5. )
  6. partition by list(store_id)(
  7. partition p0 values in( 5, 6, 7, 8),
  8. partition p1 values in( 11, 3, 12, 11),
  9. partition p2 values in( 16),
  10. partition p3 values in( 21)
  11. )

\

 注意:在使用分区时,where后面的字段必须是分区字段,才能使用到分区。

\

4、list分区和range分区混合分区

CREATETABLE sales_detail
(

product_cdCHAR2(10), --商品编码
sales_amountNUMBER(10), --
销售数量
sales_dateDATE
 --销售日

sales_stateVARCHAR2(20) --销售地区
)

PARTITIONBY RANGE(sales_date)

SUBPARTITIONBY LIST(sales_state

(

PARTITIONp2006q1 VALUES LESS THAN(TO_DATE('2006-04-01','YYYY-MM-DD')) -–1季度分区

(

SUBPARTITIONsales_beijing VALUES('BeiJing'), --BeiJing地区

SUBPARTITIONsales_shanghai VALUES('ShangHai'), --ShangHai地区

SUBPARTITIONsales_liaoning VALUES('ShenYang','DaLian') --LiaoNing地区

),
PARTITIONp2006q2 VALUES LESS THAN(TO_DATE('2006-07-01','YYYY-MM-DD')) –2
季度分区

(

SUBPARTITIONsales_beijing VALUES('BeiJing'), --BeiJing地区

SUBPARTITIONsales_shanghai VALUES('ShangHai'), --ShangHai地区

SUBPARTITIONsales_liaoning VALUES('ShenYang','DaLian') --LiaoNing地区

),
PARTITIONp2006q3 VALUES LESS THAN(TO_DATE('2006-10-01','YYYY-MM-DD')) –3
季度分区

(

SUBPARTITIONsales_beijing VALUES('BeiJing'), --BeiJing地区

SUBPARTITIONsales_shanghai VALUES('ShangHai'), --ShangHai地区

SUBPARTITIONsales_liaoning VALUES('ShenYang','DaLian') --LiaoNing地区

),
PARTITIONp2006q4 VALUES LESS THAN(TO_DATE('2007-01-01','YYYY-MM-DD')) --4
季度分区

(

SUBPARTITIONsales_beijing VALUES('BeiJing'), --BeiJing地区

SUBPARTITIONsales_shanghai VALUES('ShangHai'), --ShangHai地区

SUBPARTITIONsales_liaoning VALUES('ShenYang','DaLian') --LiaoNing地区

)

);

如果混合分区还有不解的地方可以参考 链接:

https://www.cnblogs.com/DjangoBlog/p/3992502.html 

5、分区表的限制

(1)只能对数据表的整型列进行分区,或者数据列可以通过分区函数转化成整型列

(2)最大分区数目不能超过1024

(3)如果含有唯一索引或者主键,则分区列必须包含在所有的唯一索引或者主键在内

(4)按日期进行分区很非常适合,因为很多日期函数可以用。但是对于字符串来说合适的分区函数不太多 。                             

六,insert into 增强版


一、MySQL中的replace into

功能:

插入数据前,replace into会首先根据主键或唯一索引判断是否存在相同的记录,如果存在,则先删除原来数据,然后再插入新数据;如果没有相同的记录,则直接插入。

使用形式:

1. replace into table_name(col_name, ...) values(...)

2. replace into table_name(col_name, ...) select ...

3. replace into table_name set col_name=value, ...

前两种形式用的相对较多。其中 “into” 关键字可以省略,不过最好加上 “into”,这样意思更加直观。另外,对于那些没有给予值的列,MySQL将自动为这些列赋上默认值。


二、Oracle中的merge into

功能:

与mysql中的replace into类似,在插入数据前,merge into也会根据主键判断是否有相同的记录,不同的是后面的操作,merge into对于存在的相同记录可以不做任何操作,也可以进行修改操作,但是不能有其他操作;如果没有相同记录,可以不做任何操作,也可以做插入操作,同样也不能有其他操作。

使用形式:

MERGE INTO {table_a}

USING {table|views|query}

ON {condition}

WHEN MATCHED THEN UPDATE SET {clause}

WHEN NOT MATCHED THEN INSERT VALUES {clause}

例如:

--全部男生记录
create table fzq1 as select * from fzq where sex=1;
--全部女生记录
create table fzq2 as select * from fzq where sex=0;
/*涉及到两个表关联的例子*/
--更新表fzq1使得id相同的记录中chengji字段+1,并且更新name字段。
--如果id不相同,则插入到表fzq1中.
--将fzq1表中男生记录的成绩+1,女生插入到表fzq1中
merge into fzq1 aa     --fzq1表是需要更新的表
using fzq bb            -- 关联表
on (aa.id=bb.id)        --关联条件
when matched then       --匹配关联条件,作更新处理
update set
aa.chengji=bb.chengji+1,
aa.name=bb.name         --此处只是说明可以同时更新多个字段。
when not matched then    --不匹配关联条件,作插入处理。如果只是作更新,下面的语句可以省略。
insert values( bb.id, bb.name, bb.sex,bb.kecheng,bb.chengji);

六,group by having的应用

参考:

http://www.jb51.net/article/41975.htm

http://blog.csdn.net/bingogirl/article/details/52559302

文章参考:

https://blog.csdn.net/shuaishuai123485615/article/details/56665530

猜你喜欢

转载自blog.csdn.net/u012762054/article/details/80912065