复习一下索引java
列无重复值,能够建索引:惟一索引和普通索引 汇集索引和非汇集索引均可以是惟一的。所以,只要列中的数据是惟一的,就能够在同一个表上建立一个惟一的汇集索引和多个惟一的非汇集索引。 建了索引性能获得提升!mysql
须要说明: 惟一索引必定要当心,它带有惟一约束。 须要说明2: 查询区分度 SELECT COUNT(DISTINCT 列_xx)/COUNT(*) FROM 表正则表达式
存储引擎及文件格式比较sql
建索引的目的数据库
加快查询速度,固然了,使用索引后查询有迹可循。 减小I/O操做,经过索引的路径来检索数据,不是在磁盘中随机检索。 消除磁盘排序,索引是排序的,走完索引就排序完成并发
什么时候使用索引函数
查询返回的记录数性能
排序表<40%大数据
非排序表 <7%优化
表的碎片较多(频繁增长、删除)
基础表维护时,系统要同时维护索引,不合理的索引将严重影响系统资源,主要表如今CPU和I/O上;
插入、更新、删除数据产生大量db file sequential read锁等待;
1.频繁更新的字段不适合创建索引
2.where条件中用不到的字段不适合创建索引
3.表数据能够肯定比较少的不须要建索引
4.数据重复且发布比较均匀的的字段不适合建索引(惟一性太差的字段不适合创建索引),例如性别,真假值
5. 参与列计算的列不适合建索引
预备知识-事务
ACID
原子性:一个事务(transaction)中的全部操做,要么所有完成,要么所有不完成,不会结束在中间某个环节。事务在执行过程当中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务历来没有执行过同样。
一致性:在事务开始以前和事务结束之后,数据库的完整性没有被破坏。这表示写入的资料必须彻底符合全部的预设规则,这包含资料的精确度、串联性以及后续数据库能够自发性地完成预约的工做。
隔离性:数据库容许多个并发事务同时对其数据进行读写和修改的能力,隔离性能够防止多个事务并发执行时因为交叉执行而致使数据的不一致。事务隔离分为不一样级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。
预备知识-锁
1.按照对数据操做的类型分
读锁:也称为共享锁,针对同一资源,多个读操做是能够并行进行的,而且互不影响。
写锁:也称排它锁。 当前线程写数据的时候,会阻断其余线程来读数据和写数据
2.按照 粒度来分
表锁:就是锁整个表(myisam)
行锁:就是锁单独某个表中的某一行(innodb)
叶锁:他是鉴于表锁和行数之间的一种粒度
Explain
1.Id,SQL执行的顺利的标识,SQL从大到小的执行.
2. select_type,就是select类型,能够有如下几种
3.Table,显示这一行的数据是关于哪张表的.
4.Type,这列很重要,显示了链接使用了哪一种类别,有无使用索引. 从最好到最差的链接类型为const、eq_reg、ref、range、indexhe和ALL
5.possible_keys,possible_keys列指出MySQL能使用哪一个索引在该表中找到行。
6. Key,key列显示MySQL实际决定使用的键(索引)。
7.key_len,使用的索引的长度。在不损失精确性的状况下,长度越短越好
8. Ref,ref列显示使用哪一个列或常数与key一块儿从表中选择行。
9. Rows,rows列显示MySQL认为它执行查询时必须检查的行数。
10. Extra,该列包含MySQL解决查询的详细信息,下面详细.
select_type
一、SIMPLE,简单查询
二、PRIMARY,主查询(多个表关联时)
三、UNION,联合查询
四、DEPENDENT UNION,子查询中的联合查询
五、UNION RESULT,联合的结果集
六、SUBQUERY,第一个子查询
七、 DEPENDENT SUBQUERY,子查询中第一句
八、DERIVED,派生表
type
一、system, const联接类型的一个特例。表仅有一行知足条件
二、const,表最多有一个匹配行,它将在查询开始时被读取。由于仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,由于它们只读取一次!
三、eq_ref,对于每一个来自于前面的表的行组合,从该表中读取一行。这多是最好的联接类型,除了const类型。它用在一个索引的全部部分被联接使用而且索引是UNIQUE或PRIMARY KEY。eq_ref能够用于使用= 操做符比较的带索引的列。比较值能够为常量或一个使用在该表前面所读取的表的列的表达式。
四、.ref,对于每一个来自于前面的表的行组合,全部有匹配索引值的行将从这张表中读取。若是联接只使用键的最左边的前缀,或若是键不是UNIQUE或PRIMARY KEY(换句话说,若是联接不能基于关键字选择单个行的话),则使用ref。若是使用的键仅仅匹配少许行,该联接类型是不错的。ref能够用于使用=或<=>操做符的带索引的列。
五、 ref_or_null,该联接类型如同ref,可是添加了MySQL能够专门搜索包含NULL值的行。在解决子查询中常用该联接类型的优化。六、index_merge,该联接类型表示使用了索引合并优化方法。在这种状况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
七、unique_subquery,该类型替换了下面形式的IN子查询的ref。value IN (SELECT primary_key FROM single_table WHERE some_expr)unique_subquery是一个索引查找函数,能够彻底替换子查询,效率更高。
八、index_subquery,该联接类型相似于unique_subquery。能够替换IN子查询
九、range、只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪一个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。
十、index、该联接类型与ALL相同,除了只有索引树被扫描。这一般比ALL快,由于索引文件一般比数据文件小。
十一、ALL,对于每一个来自于先前的表的行组合,进行完整的表扫描。若是表是第一个没标记const的表,这一般很差,而且一般在它状况下不好。一般能够增长更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。
Extra 这个列能够显示的信息很是多,有几十种。经常使用以下:
(1).Distinct, 一旦MYSQL找到了与行相联合匹配的行,就再也不搜索了
(2).Not exists ,使用了反链接,先查询外表,再查询内表
(3).Range checked for each Record(index map:#) 没有找到理想的索引,所以对于从前面表中来的每个行组合,MYSQL检查使用哪一个索引,并用它来从表中返回行。这是使用索引的最慢的链接之一
(4).Using filesort 看到这个的时候,查询须要优化。MYSQL须要进行额外的步骤来发现如何对返回的行排序。它根据链接类型以及存储排序键值和匹配条件的所有行的行指针来排序所有行
(5).Using index 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的所有的请求列都是同一个索引的部分的时候
(6).Using temporary 看到这个的时候,查询须要优化。这里,MYSQL须要建立一个临时表来存储结果,这一般发生在对不一样的列集进行ORDER BY上,而不是GROUP BY上
(7).Using where使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。若是不想返回表中的所有行,而且链接类型ALL或index,这就会发生,或者是查询有问题
(8).firstmatch(tb_name):5.6.x开始引入的优化子查询的新特性之一,常见于where字句含有in()类型的子查询。若是内表的数据量比较大,就可能出现这个.
(9).loosescan(m..n):5.6.x以后引入的优化子查询的新特性之一,在in()类型的子查询中,子查询返回的可能有重复记录时,就可能出现这个
MySQL执行计划的局限
•EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响状况
•EXPLAIN不考虑各类Cache
•EXPLAIN不能显示MySQL在执行查询时所做的优化工做
•部分统计信息是估算的,并不是精确值
•EXPALIN只能解释SELECT操做,其余操做要重写为SELECT后查看执行计划
分页特殊处理
Select * from fentrust e Inner join (select fid from fentrust limit 4100000, 10) a on a.fid = e.fid
Select * from fentrust e limit 4100000, 10
Select * from fentrust e where fid in(select fid from (select fid from fentrust limit 4100000, 10) a )
原理 索引覆盖最快
善用子查询
原理 子查询比join快,虽然规律不绝对,但对大表多数有效
Where条件顺序
SELECT * FROM `fentrustlog` e WHERE e.fcount > 1000 and e.famount > 300000
e.fcount > 1000:48万行
e.famount > 300000: 24行
谁先谁后? 结果是不太有效
大事务问题
尽可能避免大事务操做,提升系统并发能力。 有时没法避免,改用定时器延迟处理
不走索引的状况
SELECT ` famount ` FROM ` fentrust ` WHERE ` famount `+10=30;-- 不会使用索引,由于全部索引列参与了计算
SELECT `famount` FROM `fentrust` WHERE LEFT(`fcreateTime`,4) <1990; -- 不会使用索引,由于使用了函数运算,原理与上面相同
SELECT * FROM ` fuser` WHERE `floginname` LIKE‘138%' -- 走索引
SELECT * FROM ` fuser ` WHERE ` floginname ` LIKE "%7488%" -- 不走索引 -- 正则表达式不使用索引,这应该很好理解,因此为何在SQL中很难看到regexp关键字的缘由 -- 字符串与数字比较不使用索引;
EXPLAIN SELECT * FROM `a` WHERE `a`=1 -- 不走索引
select * from fuser where floginname='xxx' or femail='xx' or fstatus=1 --若是条件中有or,即便其中有条件带索引也不会使用。换言之,就是要求使用的全部字段,都必须创建索引, 咱们建议你们尽可能避免使用or 关键字
若是mysql估计使用全表扫描要比使用索引快,则不使用索引
大数据表优化
1.对查询进行优化,应尽可能避免全表扫描,首先应考虑在 where 及 order by 涉及的列上创建索引。
2.应尽可能避免在 where 子句中对字段进行 null 值判断,不然将致使引擎放弃使用索引而进行全表扫描,如:select id from t where num is null能够在num上设置默认值0,确保表中num列没有null值,而后这样查询:select id from t where num=0
3.应尽可能避免在 where 子句中使用!=或<>操做符,不然引擎将放弃使用索引而进行全表扫描。
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.in 和 not in 也要慎用,不然会致使全表扫描,如:select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了:select id from t where num between 1 and 3
6.下面的查询也将致使全表扫描:select id from t where name like '李%'若要提升效率,能够考虑全文检索。
7. 若是在 where 子句中使用参数,也会致使全表扫描。由于SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,若是在编译时创建访问计划,变量的值仍是未知的,于是没法做为索引选择的输入项。以下面语句将进行全表扫描:select id from t where num=@num能够改成强制查询使用索引:select id from t with(index(索引名)) where num=@num
8.应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。如:select id from t where num/2=100应改成:select id from t where num=100*2
9.应尽可能避免在where子句中对字段进行函数操做,这将致使引擎放弃使用索引而进行全表扫描。如:select id from t where substring(name,1,3)='abc' ,name以abc开头的id 应改成: select id from t where name like 'abc%'
10.不要在 where 子句中的“=”左边进行函数、算术运算或其余表达式运算,不然系统将可能没法正确使用索引。
11.在使用索引字段做为条件时,若是该索引是复合索引,那么必须使用到该索引中的第一个字段做为条件时才能保证系统使用该索引,不然该索引将不会被使用,而且应尽量的让字段顺序与索引顺序相一致。
12.不要写一些没有意义的查询,如须要生成一个空表结构:select col1,col2 into #t from t where 1=0 这类代码不会返回任何结果集,可是会消耗系统资源的,应改为这样: create table #t(...)
13.不少时候用 exists 代替 in 是一个好的选择:select num from a where num in(select num from b) 用下面的语句替换: select num from a where exists(select 1 from b where num=a.num)
14.并非全部索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即便在sex上建了索引也对查询效率起不了做用。
15. 索引并非越多越好,索引当然可 以提升相应的 select 的效率,但同时也下降了 insert 及 update 的效率,由于 insert 或 update 时有可能会重建索引,因此怎样建索引须要慎重考虑,视具体状况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。
16. 应尽量的避免更新 clustered 索引数据列,由于 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将致使整个表记录的顺序的调整,会耗费至关大的资源。若应用系统须要频繁更新 clustered 索引数据列,那么须要考虑是否应将该索引建为 clustered 索引。
17.尽可能使用数字型字段,若只含数值信息的字段尽可能不要设计为字符型,这会下降查询和链接的性能,并会增长存储开销。这是由于引擎在处理查询和链接时会逐个比较字符串中每个字符,而对于数字型而言只须要比较一次就够了。
18.尽量的使用 varchar/nvarchar 代替 char/nchar ,由于首先变长字段存储空间小,能够节省存储空间,其次对于查询来讲,在一个相对较小的字段内搜索效率显然要高些。
19.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
20.尽可能使用表变量来代替临时表。若是表变量包含大量数据,请注意索引很是有限(只有主键索引)。
21.避免频繁建立和删除临时表,以减小系统表资源的消耗。
22.临时表并非不可以使用,适当地使用它们可使某些例程更有效,例如,当须要重复引用大型表或经常使用表中的某个数据集时。可是,对于一次性事件,最好使用导出表。
23.在新建临时表时,若是一次性插入数据量很大,那么可使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是数据量不大,为了缓和系统表的资源,应先create table,而后insert。
24.若是使用到了临时表,在存储过程的最后务必将全部的临时表显式删除,先 truncate table ,而后 drop table ,这样能够避免系统表的较长时间锁定。 25.尽可能避免使用游标,由于游标的效率较差,若是游标操做的数据超过1万行,那么就应该考虑改写。
26.使用基于游标的方法或临时表方法以前,应先寻找基于集的解决方案来解决问题,基于集的方法一般更有效。
27. 与临时表同样,游标并非不可以使 用。对小型数据集使用 FAST_FORWARD 游标一般要优于其余逐行处理方法,尤为是在必须引用几个表才能得到所需的数据时。在结果集中包括“合计”的例程一般要比使用游标执行的速度快。若是开发时 间容许,基于游标的方法和基于集的方法均可以尝试一下,看哪种方法的效果更好。
28.在全部的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每一个语句后向客户端发送DONE_IN_PROC 消息。
29.尽可能避免大事务操做,提升系统并发能力。
30.尽可能避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
批量删除,而不一次性
while(true){ //每次只作1000条 “delete from logs where log_date <= ’2012-11-01’ limit 1000”; if(mysql_affected_rows == 0){ //删除完成,退出! break; } //每次暂停一段时间,释放表让其余进程/线程访问。 Thread.sleep(5000L) }
大数据表优化
创建汇总表
创建流水表
分表分库