Mysql的优化和锁机制及引擎方面的知识点

以下文章基本属于章节翻译及技术方面的大牛给我的资料,我汇总之后的发表。不喜轻喷

mysql处理批量的数据时如何提高其查询速度的方法

1、应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。
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、下面的查询也将导致全表扫描:(不能前置百分号)

select id from t where name like ‘%c%’ 

若要提高效率,可以考虑全文检索。

6、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

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 datediff(day,createdate,’2005-11-30′)=0–’2005-11-30′生成的id 

应改为:

select id from t where name like ‘abc%’ 
select id from t where createdate>=’2005-11-30′ and createdate<’2005-12-1′

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、尽量避免大事务操作,提高系统并发能力。
数据库优化方案
(1)优化索引、SQL语句、分析慢查询
(2)设计表的时候严格根据数据库的设计范式来设计数据库
(3)使用缓存,把经常访问到的数据而且不需要经常变化的数据放在缓存中,能节约磁盘1o
(4)优化硬件,采用SSD,使用磁盘队列技术(RAIDO, RAIDL, RDID5) 等
(5)采用MySQL内部自带的表分区技术,把数据分层不同的文件,能够提高磁盘的读取效率W垂直分表;把一些不经常读的数据放在一张表里,节约磁盘I/0
(7)主从分离读写;采用主从复制把数据库的读操作和写入操作分离开来
(8)分库分表分机器(数据量特别大),主要的的原理就是数据路由
(9)选择合适的表引擎,参数上的优化
(10)进行架构级别的缓存,静态化和分布式
(11)不采用全文索引
(12)采用更快的存储方式,例如Nosql存储经常访问的数据
怎样解决海量数据的存储和访问造成系统设计瓶颈的问题?
(1)水平切分数据库:可以降低单台机器的负载,同时最大限度的降低了宕机造成的损失;分库降低了单点机器的负载;分表,提高了数据操作的效率,
(2)负载均衡策略:可以降低单台机器的访问负载,降低宕机的可能性
(3)集群方案:解决了数据库宕机带来的单点数据库不能访问的问题
(4)读写分离策略:最大限度了提高了应用中读取数据的速度和并发量

怎样解决数据库高并发的问题?
(1)解决数据库高并发
(2)分表分库
(3)数据库索引
(4)redis缓存数据库
(5)读写分离
(6)负载均衡集群;将大量的并发请求分担到多个灶理节点。由于单个处理节点的故障不影响整个服务,负载均衡挚群同时也实现了高可用性。

数据库怎么优化查询效率?
(1)储存引擎选择:如果数据表需要事务处理,应该考虑使用lnnoDB,因为它完全符合ACID特性。如果不需要事务处理,使用默认存储引擎MyISAM是比较明智的
(2)分表分库,主从。
(3)对查询进行优化,要尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引
(4)应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描
(5)应尽量避免在where子句中使用!=或><操作符,否则将引擎放弃使用索引而进行全表扫描
(6)应尽量避免在where子句中使用or来连接条化如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描
(7)Update语句,如果只更改1.2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。

如果每天有5T的用户数据量需要存入mysql中怎么优化数据库?
1、尽量使数据库一次性写入Data File
2、减少数据库的checkpoint操作
3、程序上尽量缓冲数据,进行批量式插入与提交
4、减少系统的10冲突

如何查找MySQL中查询慢的SQL语句
(1)slow_query_log这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句。
(2)long_quew-time当SQL语句执行时间超过此数值时,就会被记录到日志中,建议设置为1或者更短。

数据库负载均衡
对客户端来说,整个群集可以视为一台具有超高性能的独立服务器。
(1)实现原理
实现数据库的负载均衡技术,首先要有一个可以控制连接数据库的控制端。在这里,它截断了数据库和程序的直接连接,由所有的程序来访问这个中间层,然后再由中间层来访问数据库。这样,我们就可以具体控制访问某个数据库了。然后还可以根据数据库的当前负载采取有效的均衡策略,来调整每次连接到哪个数据库。
(2)实现多数据数据同步
对于负载均衡,最重要的就是所有服务器的数据都是实时同步的。这是一个集群所必需的,因为,如果数据不实时、不同步,那么用户从一台服务器读出的数据,就有别于从另一台服务器读出的数据,这是不能允许的。所以必须实现数据库的数据同步。这样,在查询的时候就可以有多个资源,实现均衡。比较常用的方法是Moebius for SQL Server集群,Moebrus for SQL Server集群采用将核心程序驻留在每个机器的数据库中的办法,这个核心程序称为Moebius for SQL Server中间件,主要作用是监测数据库内数据的变化并将变化的数据同步到其他数据库中。数据同步完成后客户端才会得到响应,同步过程是并发完成,所以同步到多个数据库和同步到一个数据库的时间基本相等;另外同步的过程是在事务的环境下完成的,保证了多份数据在任何时刻数据的一致性。正因为Moebius中间件宿主在数据库中的创新,让中间件不但能知道数据的变化而且知道引起数据变化的SQL语句,根据SQL语句的类型智能的采取不同的数据同步的策略以保证数据同步成本的最小化。数据条数很少,数据内容也不大,则直接同步数据数据条数很少,但是里面包含大数据类型,比如文本,二进制数据等,则先对数据进行压缩然后再同步,从而减少网络带宽的占用和传输所用的时间。数据条数很多,此时中间件会拿到造成数据变化的SQL语句,然后对SQL语句进行解析,分析其执行计划和执行成本,并选择是同步数据还是同步SQL语句到其他的数据库中。此种情况应用在对表结构进行调整或者批量更改数据的时候非常有用。
优点
(1)扩展性强地增加数据当系统要更高数据库处理速度时,只要简单库服务器就可以得到扩展
(2)可维护性:当某节点发生故障时,系统会自动检测故障并转移故障节点的应用,保证数据库的持续工作。
(3)安全性:因为数据会同步到多台服务器上,可以实现数据集的冗余,通过多份数据来保证安全性。另外它成功地将数据库放到了内网之中,更好地保护了数据库的安全性。
(4)易用性:对应用来说完全透明,集群暴露出来的就是一个IP.
缺点
(1)不能够按照Web服务器的处理能力分配负载。
(2)负载均衡器(控制端)故障

MySQL各存储引擎使用了三种类型(级别)的锁定机制:表级锁定,行级锁定和页级锁定。
1.表级锁定(table-level)
表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,大打折扣。使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。
2.行级锁定(row-level)
行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。
由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。
3.页级锁定(page-level)
页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。使用页级锁定的主要是BerkeleyDB存储引擎。

总的来说,MySQL这3种锁的特性可大致归纳如下:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
适用:从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;
而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统

死锁
通常来说,死锁都是应用设计的问题,通过调整业务流程、数据库对象设计、事务大小,以及访问数据库的SQL语句,
绝大部分死锁都可以避免。下面就通过实例来介绍几种避免死锁的常用方法:
(1)在应用中,如果不同的程序会并发存取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会。
(2)在程序以批量方式处理数据的时候,如果事先对数据排序,保证每个线程按固定的顺序来处理记录,也可以大大降低出现死锁的可能。
(3)在事务中,如果要更新记录,应该直接申请足够级别的锁,而不应先申请共享锁,更新时再申请排斥锁,因为当用户申请排斥锁时,其他事务可能又已经获得了相同记录的共享锁,从而造成锁冲突,甚至死锁。
(4)在REPEATABLE-READ隔离级别下,如果两个线程同时对相同条件记录用SELECT…FOR UPDATE加排斥锁,在没有符合该条件记录情况下,两个线程都会加锁成功。程序发现记录尚不存在,就试图插入一条新记录,
如果两个线程都这么做,就会出现死锁。这种情况下,将隔离级别改成READ COMMITTED,就可避免问题。
(5)当隔离级别为READ COMMITTED时,如果两个线程都先执行SELECT…FOR UPDATE,判断是否存在符合条件的记录,如果没有,就插入记录。此时,只有一个线程能插入成功,另一个线程会出现锁等待,
当第1个线程提交后,第2个线程会因主键重复而出错,但虽然这个线程出错了,却会获得一个排斥锁。
这时如果有第3个线程又来申请排斥锁,也会出现死锁。
对于这种情况,可以直接做插入操作,然后再捕获主键重异常,或者在遇到主键重错误时,总是执行ROLLBACK释放获得的排斥锁。

在MySQL数据库中,常用的引擎主要就是2个:Innodb和MyIASM。
首先:
1.简单介绍这两种引擎,以及该如何去选择
2.这两种引擎所使用的数据结构是什么。
a.Innodb引擎,Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。
它的设计的目标就是处理大数据容量的数据库系统。它本身实际上是基于Mysql后台的完整的系统。
Mysql运行的时候,Innodb会在内存中建立缓冲池,用于缓冲数据和索引。
但是,该引擎是不支持全文搜索的。同时,启动也比较的慢,它是不会保存表的行数的。
当进行Select count(“”) from table“”指令的时候,需要进行扫描全表。
所以当需要使用数据库的事务时,该引擎就是首选。由于锁的粒度小,写操作是不会锁定全表的。
所以在并发度较高的场景下使用会提升效率的。
b.MyIASM引擎,它是MySql的默认引擎,但不提供事务的支持,
也不支持行级锁和外键。因此当执行Insert插入和Update更新语句时,
即执行写操作的时候需要锁定这个表。所以会导致效率会降低。
不过和Innodb不同的是,MyIASM引擎是保存了表的行数,
于是当进行Select count(“”) from table“”语句时,可以直接的读取已经保存的值而不需要进行扫描全表。
所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的。可以将MyIASM作为数据库引擎的首先。
补充2点:
**c.**大容量的数据集时趋向于选择Innodb。因为它支持事务处理和故障的恢复。
Innodb可以利用数据日志来进行数据的恢复。主键的查询在Innodb也是比较快的。
**d.**大批量的插入语句时(这里是INSERT语句)在MyIASM引擎中执行的比较的快,
但是UPDATE语句在Innodb下执行的会比较的快,尤其是在并发量大的时候。
2.两种引擎所使用的索引的数据结构是什么?
答案:都是B+树!
MyIASM引擎,B+树的数据结构中存储的内容实际上是实际数据的地址值。
也就是说它的索引和实际数据是分开的,只不过使用索引指向了实际数据。这种索引的模式被称为非聚集索引。
Innodb引擎的索引的数据结构也是B+树,只不过数据结构中存储的都是实际的数据,这种索引有被称为聚集索引。

以上文章基本属于章节翻译及技术方面的大牛给我的资料,我汇总之后发表。不喜轻喷

猜你喜欢

转载自blog.csdn.net/weixin_44266137/article/details/85258882