MySQL数据库for面试

本篇涉及到的问题:MySQL引擎;  什么是基本表、视图、游标;  char和varchar的区别及使用场景;  MySQL中,索引、主键、唯一索引、联合索引的区别,对数据库的读写性能的影响;  为数据库表建立索引的原则、目的及对DBS的负面影响;  MySQL语句优化;MySQL执行计划分析;MySQL复制原理。

目录

MySQL引擎

什么是基本表、视图、游标

char和varchar的区别及使用场景

MySQL中,索引、主键、唯一索引、联合索引的区别,对数据库的读写性能的影响

为数据库表建立索引的原则、目的及对DBS的负面影响

提高sql语句效率的技巧:

1.大批量插入数据:

 2.优化INSERT语句

3.查询优化

4.注意不使用索引的情况: 

select Count (*)和Select Count(1)以及Select Count(column)区别:

索引列上计算引起的索引失效及优化措施以及注意事项:

怎么样执行计划分析?

MySQL复制原理:


MySQL引擎

    MySQL的核心就是存储引擎。 MySQL的存储引擎是针对表进行设置的,一个数据库中不同的表可以设置成不同的存储引擎,以适用不同领域的数据库应用需要。主要的数据库引擎如下:

  1.  MyISAM:5.5之前默认的MySQL插件式存储引擎,不支持事务,不支持外键,只支持表级锁,内存和硬盘占用率低,优势是访问速度快,对事物完整性没有要求,以select、insert为主的应用基本上都可以使用这个引擎;使用场景:存日志、大批量数据导入和初始化。
  2.  InnoDB:5.5之后默认的存储引擎,提供了具有提交、回滚、崩溃恢复能力的事务安全,支持外键并提供了行级锁,其劣势在于写的处理效率相对较低,并且会占用更多的磁盘空间以保留数据和索引。
  3.  Memory(基于内存):使用存于内存中的内容来创建表,MEMORY类型的表数据存于内存,访问非常的快,默认使用Hash索引,一旦数据库服务重启或关闭,表中的数据就会丢失。
  4.  Merge:Merge存储的是一组MyISAM表组合,这些MyISAM表结构完全相同。Merge表本身没有数据,对Merge表的CRUD操作都是通过内部的MyISAM表进行的。类似于视图。
  5. BDB:可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其他事务特性。
  6.  Archive:为大量很少引用的历史、归档、或安全审计信息的存储和检索提供了完美的解决方案。
  7. Federated:能够将多个分离的MySQL服务器链接起来,从多个物理服务器创建一个逻辑数据库。十分适合于分布式环境或数据集市环境。
  8. Cluster/NDB:MySQL的簇式数据库引擎,尤其适合于具有高性 能查找要求的应用程序,这类查找需求还要求具有最高的正常工作时间和可用性。
  9. Other:其他存储引擎包括CSV(引用由逗号隔开的用作数据库表的文件),Blackhole(用于临时禁止对数据库的应用程序输入),以及Example引擎(可为快速创建定制的插件式存储引擎提供帮助)。

对于整个服务器或方案,并不一定要使用相同的存储引擎,可以为方案中的每个表使用不同的存储引擎。

下面详细介绍InnoDB引擎和MyISAM引擎:

Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别。该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQL后台的完整数据库系统,MySQL运行时InnoDB会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎不支持FULLTEXT类型的索引,而且它没有保存表的行数,当SELECT COUNT(*) FROM TABLE时需要扫描全表。当需要使用数据库事务时,该引擎当然是首选。由于锁的粒度更小,写操作不会锁定全表,所以在并发较高时,使用Innodb引擎会提升效率。但是使用行级锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表。

MyIASM引擎是MySQL默认的引擎,但是它没有提供对数据库事务的支持,也不支持行级锁和外键,因此当INSERT(插入)或UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些。不过和InnoDB不同,MyIASM中存储了表的行数,于是SELECT COUNT(*) FROM TABLE时只需要直接读取已经保存好的值而不需要进行全表扫描。如果表的读操作远远多于写操作且不需要数据库事务的支持,那么MyIASM也是很好的选择。

两者主要区别:

1、MyIASM是非事务安全的,而InnoDB是事务安全的

2、MyIASM锁的粒度是表级的,而InnoDB支持行级锁

3、MyIASM支持全文类型索引,而InnoDB不支持全文索引

4、MyIASM相对简单,效率上要优于InnoDB,小型应用可以考虑使用MyIASM

5、MyIASM表保存成文件形式,跨平台使用更加方便

应用场景:

1、MyIASM管理非事务表,提供高速存储和检索以及全文搜索能力,如果再应用中执行大量select操作,应该选择MyIASM。

2、InnoDB用于事务处理,具有ACID事务支持等特性,如果在应用中执行大量insert和update操作,应该选择InnoDB。

两种引擎所使用的索引的数据结构(都是B+树)

    MyIASM引擎,B+树的数据结构中存储的内容实际上是实际数据的地址值。也就是说它的索引和实际数据是分开的,只不过使用索引指向了实际数据。这种索引的模式被称为非聚集索引

    Innodb引擎的索引的数据结构也是B+树,只不过数据结构中存储的都是实际的数据,这种索引有被称为聚集索引

 

 

什么是基本表、视图、游标

    基本表是本身独立存在的表,在 SQL 中一个关系就对应一个表。 是一个虚表  

    视图是从一个或几个基本表导出的表。视图本身不独立存储在数据库中,所以视图是一种虚表。而具有和物理表相同的功能,可以对视图进行增,改,查,操作。另外,对视图的修改不影响基本表,相比多表查询,它使得我们获取数据更容易。

    游标是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。

 

 

char和varchar的区别及使用场景

    char是一种固定长度的类型,varchar则是一种可变长度的类型,它们的区别是:  

    char(M)类型的数据列里,每个值都占用M个字节,如果某个长度小于M,MySQL就会在它的右边用空格字符补足(在检索操作中那些填补出来的空格字符将被去掉)。在varchar(M)类型的数据列里,每个值只占用刚好够用的字节再加上一个用来记录其长度的字节(即总长度为L+1字节)。 

varchar得适用场景

    ☆字符串列得最大长度比平均长度大很多     ☆字符串很少被更新,容易产生存储碎片   ☆使用多字节字符集存储字符串。

char的使用场景:

    ☆存储具有近似得长度(md5值,身份证,手机号)    ☆长度比较短小得字符串(因为varchar需要额外空间记录字符串长度)

    ☆更适合经常更新的字符串,更新时不会出现页分裂得情况,避免出现存储碎片,获得更好的io性能。

 

 

 

MySQL中,索引、主键、唯一索引、联合索引的区别,对数据库的读写性能的影响

   索引是一种特殊的文件(InnoDB数据库表上的索引是表空间的一个组成部分),它们包含着数据库表里所有记录的引用指针。

   普通索引的唯一任务是加快对数据的访问速度,有KEY或INDEX关键字定义。普通索引允许被索引的数据列包含重复的值,如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义成一个唯一索引,唯一索引保证数据记录的唯一性。

    主键是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字PRIMARY KEY创建。

    索引可以覆盖多个数据列,比如INDEX(columnA,columnB)索引,这就是联合索引

    索引对数据库的读写性能的影响索引可以极大的提高数据的查询速度,但是会降低数据的插入、删除和更新表的速度,因为在执行写操作的时候,还要操作索引文件。

 

 

 

为数据库表建立索引的原则、目的及对DBS的负面影响

★ 建立索引的原则:

     ☆在最频繁使用的、用以缩小查询范围的字段上建立索引   ☆在频繁使用的,用以排序的字段上建立索引

     注:这两种情况最好不要建立索引:一是对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引;二是对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等。

◆ 建立索引的目的:

   ◇快速访问数据表中的特定信息,提高检索速度    ◇创建唯一性索引,保证数据库表中每一行数据的唯一性

   ◇加速表和表之间的连接    ◇使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间

●索引对数据库系统的负面影响:
    ○ 创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加;

    ○ 索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间  ;

    ○ 当对表进行增、删、改、的时候索引也要动态维护,这样就降低了数据的维护速度。

 

 

提高sql语句效率的技巧:

1.大批量插入数据:

 ▲大批量数据插入空表,可将表设置成MyISAM,并通过disable keys将唯一索引关闭;

 ▲大批量插入非空InnoDB表,可采取:

     ①导入数据时按照逐渐顺序排列;

     ②导入数据前使用set UNIQUE_CHECKS=0,关闭唯一性校验,导入后恢复;

     ③如果使用了自动提交(一条一条提交),建议在导入前执行SET AUTOCOMMIT=0(批量提交 ),关闭自动提交,导入后恢复

 2.优化INSERT语句

  ▲尽量使用多个值表的insert语句,降低连接、关闭的消耗;例如:insert into user values(1,“张三”),(2,“李四”),(...),... 。

  ▲将索引文件和数据文件分在不同的磁盘上存放;

  ▲从一个文本文件装入一个表时,使用LOAD DATE INFILE,比一般的inser语句快20倍

 

3.查询优化

 ▲ 尽量减少额外的排序,通过索引直接返回有序数据;where条件和order by使用相同的索引,并且order by的顺序和索引顺序相同,并且order by的字段都是升序或者都是降序;

 ▲尽量只选择必要的字段,提高SQL性能;

 ▲ 能用关联查询就不要使用子查询;

 ▲对于包含or的查询语句,如果要利用索引,则or之间的每个条件都必须用到索引,否则应该考虑增加索引;

 ▲优化分页:①在索引上完成排序分页的操作,然后根据主键关联回原表查询所需的其他列 ②把limit查询转化为某个位置的查询。

 

4.注意不使用索引的情况: 

 ▲如果MySQL估计使用索引比全表扫描更慢,则不用索引;

 ▲用or分隔开的条件,如果or前的条件中的列有索引,而后面的列没有索引,那么涉及到的索引都不会被用到;

 ▲复合索引,如果索引列不是符合索引的第一部分,则不使用索引(即不符合最左前缀);

 ▲如果like是以“%”开始的,则该列上的索引不会被使用;

 ▲如果列为字符串,则where条件中必须将字符常量值加引号,否则即使该列上存在索引,也不会被使用;

 ▲not in、not exist、!=或<>这些操作符不走索引;

 ▲不要在where字句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

 


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

▲应尽量避免在where子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。

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

▲应尽量避免在 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

▲模糊查询以%开头的查询也将导致全表扫描,例:select id from t where name like '%abc%'。

▲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;

▲如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
     select id from t where num=@num; 可以改为强制查询使用索引: select id from t with(index(索引名)) where num=@num;

▲应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
     select id from t where num/2=100;   应改为:   select id from t where num=100*2;

▲应尽量避免在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';

▲不要在 where 子句中的“=”【左边】进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

▲在使用索引字段作为条件时,如果该索引是【复合索引】,那么必须使用到该索引中的【第一个字段】作为条件时才能保证系统使用该索引,否则该索引将不会被使用。并且应【尽可能】的让字段顺序与索引顺序相一致。(字段顺序也可以不与索引顺序一致,但是一定要包含【第一个字段】。)

▲不要写一些没有意义的查询,如需要生成一个空表结构:
    select col1,col2 into #t from t where 1=0; 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成:create table #t(...);

▲很多时候用 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);

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

▲索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

▲应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。

▲尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

▲尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

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

▲尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

▲避免频繁创建和删除临时表,以减少系统表资源的消耗。

▲.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

▲临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

▲尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

▲使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

▲与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

▲在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。

▲尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

▲尽量避免大事务操作,提高系统并发能力。


 


select Count (*)和Select Count(1)以及Select Count(column)区别:

    一般情况下,Select Count (*)和Select Count(1)两着返回结果是一样的。
    假如表沒有主键(Primary key), 那么count(1)比count(*)快;如果有主键的話,那主键作为count的条件时候count(主键)最快; 如果表中只有一个字段的话那count(*)就是最快的。count(*) 跟 count(1) 的结果一样,都包括对NULL的统计,而count(column) 是不包括NULL的统计 。

 

索引列上计算引起的索引失效及优化措施以及注意事项:

    创建索引、优化查询以便达到更好的查询优化效果。但实际上,MySQL有时并不按我们设计的那样执行查询。MySQL是根据统计信息来生成执行计划的,这就涉及索引及索引的刷选率,表数据量,还有一些额外的因素
   Each table index is queried, and the best index is used unless the optimizer believes that it is more efficient to use a table scan. At one time, a scan was used based on whether the best index spanned more than 30% of the table, but a fixed percentage no longer determines the choice between using an index or a scan. The optimizer now is more complex and bases its estimate on additional factors such as table size, number of rows, and I/O block size.
    简而言之,当MySQL认为符合条件的记录在30%以上,它就不会再使用索引因为mysql认为走索引的代价比不用索引代价大,所以优化器选择了自己认为代价最小的方式。事实也的确如此,是MYSQL认为记录是30%以上,而不是实际MYSQL去查完再决定的。都查完了,还用什么索引啊!MYSQL会先估算,然后决定是否使用索引。

 

怎么样执行计划分析?

  通过explain命令获取MySQL如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序;explain分析后的结果解析:

▲ select_type:查询的类型,主要区分普通查询、联合查询、子查询等复杂的查询

   ① SIMPLE:简单的select查询,查询中不包含子查询或者union;

   ② PRIMARY:查询中包含任何复杂的子部分,最外层查询被记为primary;

   ③ SUNBQUERY:在select或者where列表中包含了子查询;

   ④ UNION:若第二个select出现在union之后,则被标记为union;若union包含在from字句的子查询中,外层select将被标记为derived;

type:访问类型,sql优化中很重要的一个指标,接过值从好到坏一次:system>const>eq_ref>ref>range>index>ALL

一般来说,好的sql查询至少达到range级别,最好能达到ref;

   ① system:表中只有一行记录(等于系统表),这是const的特例,平时不会出现,可以忽略;

   ② const:表示通过索引一次就找到了,const用于比较primary key或者unique索引;

   ③ seq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配;

   ④ ref:非唯一性索引扫描,返回匹配某个单独值的所有行;

   ⑤ range:索引范围扫描;

   ⑥ index:索引全扫描;

   ⑦ ALL:全表扫描;

▲ possible_keys :查询涉及到的字段上存在索引,则该索引将被列出,但不一定被查询实际使用 ;

▲ key :实际使用的索引,如果为NULL,则没有使用索引;

▲ key_len :索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实 际使用长度,理论上长度越短越好;

▲ ref :显示索引的哪些列;

▲ rows :根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数

▲ Extra :不适合在其他字段中显示,但是十分重要的额外信息

优化目标:

① 根据需求建立索引;② 每个查询都要使用索引以提高查询效率,至少达到range级别,最好能达到ref;③ 追求key_len和rows最小。

 

MySQL复制原理:

1.主库在数据提交时会把数据变更作为事件记录在二进制日志文件Binlog中,可通过参数sync_binlog控制binlog日志刷新到磁盘的频率;

2.主库推送二进制日志文件binlog中的事件到从库的中继日志Relay Log,之后从库根据中继日志RelayLog重做数据变更操作,通过逻辑复制达到主从库的数据一致;

3.MySQL通过3个线程来完成主从库之间的数据同步,其中binlog dump线程跑在主库上,I/O线程sql线程跑在从库上。

当从库启动复制时,首先创建I/O线程连接主库,主库随后创建binlog 

    当从库启动复制时,首先创建I/O线程连接主库,主库随后创建binlog dump线程读取数据库事件并发送给I/O线程,I/O线程获取到的事件数据后更新到从库的中继日志replay log中去,之后从库上的sql线程读取中继日志中更新的数据库事件并应用;

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值