当前位置:首页 » 编程语言 » mysqlsql优化面试
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

mysqlsql优化面试

发布时间: 2022-12-07 19:23:44

A. sql中一次性查询10万条记录怎么提高查询效率

回答他还不简单 你给他说

您好:首先呢 10万条数据的表是算是比较小的表了,如果数据量达到千万和亿的话那我可以根据特定字段设置分区,然后在非分区字段建立索引,查询的时候走索引如果就只有10万数据的话就不用分区了建立索引就可以.设计好表结构后关键的是sql的优化.当然那种很简单的优化,象什么>=3用>4之类的我就不说了 sql优化比较明显的就是把结果集最少的塞选条件的表放后面,将中间表作为基础表.索引上不用运算符等!如果效果不理想就查看执行计划 分析后进一步优化 估计有些菜比面试官被你一弄他就昏了 然后你可以鄙视下他 就你那水平还考我优化 你自己会多少啊.开玩笑的哈 .和他吹吹得他觉得你比他还牛比 然后你可以给他说说共享池 PGA 数据块大小啊 操作系统的命中率 和垃圾存储过程 行了 他不要你都难了 如果你是面试初级程序员的话

B. SQL执行与优化

SQL优化

执行计划,表关联查询顺序,优化策略与思路

下面再向前走一些,容我根据自己的认识说一下查询执行的流程是怎样的:

1.连接

1.1客户端发起一条Query请求,监听客户端的‘连接管理模块’接收请求

1.2将请求转发到‘连接进/线程模块’

1.3调用‘用户模块’来进行授权检查

1.4通过检查后,‘连接进/线程模块’从‘线程连接池’中取出空闲的被缓存的连接线程和客户端请求对接,如果失败则创建一个新的连接请求

2.处理

2.1先查询缓存,检查Query语句是否完全匹配,接着再检查是否具有权限,都成功则直接取数据返回

2.2上一步有失败则转交给‘命令解析器’,经过词法分析,语法分析后生成解析树

2.3接下来是预处理阶段,处理解析器无法解决的语义,检查权限等,生成新的解析树

2.4再转交给对应的模块处理

2.5如果是SELECT查询还会经由‘查询优化器’做大量的优化,生成执行计划

2.6模块收到请求后,通过‘访问控制模块’检查所连接的用户是否有访问目标表和目标字段的权限

2.7有则调用‘表管理模块’,先是查看table cache中是否存在,有则直接对应的表和获取锁,否则重新打开表文件

2.8根据表的meta数据,获取表的存储引擎类型等信息,通过接口调用对应的存储引擎处理

2.9上述过程中产生数据变化的时候,若打开日志功能,则会记录到相应二进制日志文件中

3.结果

3.1Query请求完成后,将结果集返回给‘连接进/线程模块’

3.2返回的也可以是相应的状态标识,如成功或失败等

3.3‘连接进/线程模块’进行后续的清理工作,并继续等待请求或断开与客户端的连接

接下来再走一步,让我们看看一条SQL语句的前世今生。

首先看一下示例语句

示例语句

执行顺序

SQL解析

1. FROM

当涉及多个表的时候,左边表的输出会作为右边表的输入,之后会生成一个虚拟表VT1。

(1-J1)笛卡尔积

计算两个相关联表的笛卡尔积(CROSS JOIN) ,生成虚拟表VT1-J1。

两次全表扫描

哈希索引,查找复杂度都是 O(1)

2. WHERE

对VT1过程中生成的临时表进行过滤,满足WHERE子句的列被插入到VT2表中。

注意:

此时因为分组,不能使用聚合运算;也不能使用SELECT中创建的别名;

与ON的区别:

如果有外部列,ON针对过滤的是关联表,主表(保留表)会返回所有的列;

如果没有添加外部列,两者的效果是一样的;

应用:

对主表的过滤应该放在WHERE;

对于关联表,先条件查询后连接则用ON,先连接后条件查询则用WHERE;

hash join 哈希连接 驱动表和被驱动表都只会访问0次或1次

应用场景:一个大表一个小表/表上没有索引/返回结果集比较大

3. GROUP BY

这个子句会把VT2中生成的表按照GROUP BY中的列进行分组。生成VT3表。

注意:

其后处理过程的语句,如SELECT,HAVING,所用到的列必须包含在GROUP BY中,对于没有出现的,得用聚合函数;

原因:

GROUP BY改变了对表的引用,将其转换为新的引用方式,能够对其进行下一级逻辑操作的列会减少;

原作者的理解是:

根据分组字段,将具有相同分组字段的记录归并成一条记录,因为每一个分组只能返回一条记录,除非是被过滤掉了,而不在分组字段里面的字段可能会有多个值,多个值是无法放进一条记录的,所以必须通过聚合函数将这些具有多值的列转换成单值;

GROUP BY 重新聚合查询

4. HAVING

这个子句对VT3表中的不同的组进行过滤,只作用于分组后的数据,满足HAVING条件的子句被加入到VT4表中。

7.LIMIT

LIMIT子句从上一步得到的VT6虚拟表中选出从指定位置开始的指定行数据。

注意:

offset和rows的正负带来的影响;

当偏移量很大时效率是很低的,可以这么做:

采用子查询的方式优化,在子查询里先从索引获取到最大id,然后倒序排,再取N行结果集

采用INNER JOIN优化,JOIN子句里也优先从索引获取ID列表,然后直接关联查询获得最终结果

当前未用到索引,

三次full scan , table1 AS a / table2 AS b / GROUP BY

尽量少做重复的工作

控制同一语句的多次执/减少多次的数据转换/

杜绝不必要的子查询和连接表,子查询在执行计划一般解释成外连接,多余的连接表带来额外的开销

关于临时表和表变量的选择

临时表产生使用SELECT INTO和CREATE TABLE + INSERT INTO的选择,一般情况下,SELECT INTO会比CREATE TABLE + INSERT INTO的方法快很多,但是SELECT INTO会锁定TEMPDB的系统表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用户并发环境下,容易阻塞其他进程,所以建议,在并发系统中,尽量使用CREATE TABLE + INSERT INTO,而大数据量的单个语句使用中,使用SELECT INTO。

子查询的用法

相关子查询可以用IN、NOT IN、EXISTS、NOT EXISTS引入

NOT IN、NOT EXISTS的相关子查询可以改用LEFT JOIN代替写法

如果保证子查询没有重复 ,IN、EXISTS的相关子查询可以用INNER JOIN 代替

IN``的相关子查询用EXISTS代替

不要用 COUNT (*)的子查询判断是否存在记录,最好用 LEFT` `JOIN 或者EXISTS,比如有人写这样的语句:

建立索引后,并不是每个查询都会使用索引,在使用索引的情况下,索引的使用效率也会有很大的差别。只要我们在查询语句中没有强制指定索引,

不要对索引字段进行运算,而要想办法做变换

不要对索引字段进行格式转换

不要对索引字段使用函数

不要对索引字段进行多字段连接

join关联查询的计算是很复杂的,特别是数据量比较大的情况下,实际情况还是拆解较快的

Join拆解的核心就是利用In关键字

要么用空间换时间,要么用时间换空间

多表连接的连接条件对索引的选择有着重要的意义,所以我们在写连接条件条件的时候需要特别注意。

A、多表连接的时候,连接条件必须写全,宁可重复,不要缺漏。

B、连接条件尽量使用聚集索引

C、注意ON、WHERE和HAVING部分条件的区别

ON是最先执行, WHERE次之,HAVING最后,因为ON是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,WHERE也应该比 HAVING快点的,因为它过滤数据后才进行SUM,在两个表联接时才用ON的,所以在一个表的时候,就剩下WHERE跟HAVING比较了

考虑联接优先顺序:

(1)INNER JOIN

(2)LEFT JOIN (注:RIGHT JOIN 用 LEFT JOIN 替代)

(3)CROSS JOIN

索引并不适用于所有情况:a.少量数据;b.频繁进行改动的字段,不适合做索引;c.很少使用的字段,不需要加索引

索引会提高数据查询效率,但是会降低“增、删、改”的效率。当不使用索引的时候,我们进行数据的增删改,只需要操作源表即可,但是当我们添加索引后,不仅需要修改源表,也需要再次修改索引,很麻烦。

先执行顺序, 是否走索引, 有无类型转换

18000 字的SQL优化大全

步步深入:MySQL架构总览->查询执行流程->SQL解析顺序

MySQL索引总结(4)——btree与hash区别

C. mysql如何优化以下语句,查询耗时太久了

根据所描述的问题,可尝试在mms_profitcenter 的FOrderID ,FSuffix列上建立索引,再查询试试。 下面提供30种mysql常用优化方法供参考:
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

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

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 '%abc%'
若要提高效率,可以考虑全文检索。

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.尽量避免大事务操作,提高系统并发能力。

D. MySql中Sql的执行过程

如果查询缓存没有命中,那么SQL请求会进入分析器,分析器是用来分辨SQL语句的执行目的,其执行过程大致分为两步:

表1 语法分析关键字然后再通过语法规则解析,判断输入的SQL 语句是否满足MySQL语法,并且生成图5的语法树。由SQL语句生成的四个单词中,识别出两个关键字,分别是select 和from。根据MySQL的语法Select 和 from之间对应的是fields 字段,下面应该挂接username;在from后面跟随的是Tables字段,其下挂接的是userinfo。

优化器的作用是对SQL进行优化,生成最有的执行方案。如图6所示,前面提到的SQL解析器通过语法分析和语法规则生成了SQL语法树。这个语法树作为优化器的输入,而优化器(黄色的部分)包含了逻辑变换和代价优化两部分的内容。在优化完成以后会生成SQL执行计划作为整个优化过程的输出,交给执行器在存储引擎上执行。

所处的位置如上图所示,这节的重点在优化器中的逻辑变换和代价优化上。

逻辑变换也就是在关系代数基础上进行变换,其目的是为了化简,同时保证SQL变化前后的结果一致,也就是逻辑变化并不会带来结果集的变化。其主要包括以下几个方面:

这样讲概念或许有些抽象,通过图7 来看看逻辑变化如何在SQL中执行的吧。

如图7所示,从上往下共有4个步骤:
1. 针对存在的SQL语句,首先通过“否定消除”,去掉条件判断中的“NOT”。语句由原来的“or”转换成“and”,并且大于小于符号进行变号。蓝色部分为修改前的SQL,红色是修改以后的SQL。2. 等值传递,这一步很好理解分别降”t2.a=9” 和”t2.b=5”分别替换掉SQL中对应的值。3. 接下来就是常量表达式计算,将“5+7”计算得到“12”。4. 最后是常量表达式计算后的化简,将”9<=10”化简为”true”带入到最终的SQL表达式中完成优化。

代价优化是用来确定每个表,根据条件是否应用索引,应用哪个索引和确定多表连接的顺序等问题。为了完成代价优化,需要找到一个代价最小的方案。因此,优化器是通过基于代价的计算方法来决定如何执行查询的(Cost-based Optimization)。简化的过程如下:

这里将配置操作的代价分为MySQL 服务层和MySQL 引擎层,MySQL 服务层主要是定义CPU的代价,而MySQL 引擎层主要定义IO代价。MySQL 5.7 引入了两个系统表mysql.server_cost和mysql.engine_cost来分别配置这两个层的代价。如下:MySQL 服务层代价保存在表server_cost中,其具体内容如下:

由上可以看出创建临时表的代价是很高的,尤其是内部的myisam或innodb临时表。MySQL 引擎层代价保存在表engine_cost中,其具体内容如下:

目前io_block_read_cost和memory_block_read_cost默认值均为1,实际生产中建议酌情调大memory_block_read_cost,特别是对普通硬盘的场景。MySQL会根据SQL查询生成的查询计划中对应的操作从上面两张代价表中查找对应的代价值,并且进行累加形成最终执行SQL计划的代价。再将多种可能的执行计划进行比较,选取最小代价的计划执行。

当分析器生成查询计划,并且经过优化器以后,就到了执行器。执行器会选择执行计划开始执行,但在执行之前会校验请求用户是否拥有查询的权限,如果没有权限,就会返回错误信息,否则将会去调用MySQL引擎层的接口,执行对应的SQL语句并且返回结果。例如SQL:“SELECT * FROM userinfo WHERE username = 'Tom';“假设 “username“ 字段没有设置索引,就会调用存储引擎从第一条开始查,如果碰到了用户名字是” Tom“, 就将结果集返回,没有查找到就查看下一行,重复上一步的操作,直到读完整个表或者找到对应的记录。需要注意SQL语句的执行顺序并不是按照书写顺序来的,顺序的定义会在分析器中做好,一般是按照如下顺序:

如果命中的记录比较多,应用会从MySql Server一批批获取数据

本文从MySQL中SQL语句的执行过程作为切入点,首先介绍了查询请求的执行流程,其中将MySQL的处理分为MySQL Server层和MySQL存储引擎层。通过介绍SQL语句的流转,引出了后面要介绍的5大组件,他们分别是:连接器、查询缓存、分析器、优化器、执行器。后面的内容中对每个组件进行了详细的介绍。连接器,负责身份认证和权限鉴别;查询缓存,将查询的结果集进行缓存,提高查询效率;分析器,对SQL语句执行语法分析和语法规则,生成语法树和执行计划;优化器,包括逻辑变换和代价优化;执行器,在检查用户权限以后对数据进行逐条查询,整个过程遵守SQL语句的执行顺序。

E. 北大青鸟java培训:mysql数据库的优化方法

我们都知道,服务器数据库的开发一般都是通过java或者是PHP语言来编程实现的,而为了提高我们数据库的运行速度和效率,数据库优化也成为了我们每日的工作重点,今天,河北IT培训http://www.kmbdqn.cn/就一起来了解一下mysql服务器数据库的优化方法。
为什么要了解索引真实案例案例一:大学有段时间学习爬虫,爬取了知乎300w用户答题数据,存储到mysql数据中。
那时不了解索引,一条简单的“根据用户名搜索全部回答的sql“需要执行半分钟左右,完全满足不了正常的使用。
案例二:近线上应用的数据库频频出现多条慢sql风险提示,而工作以来,对数据库优化方面所知甚少。
例如一个用户数据页面需要执行很多次数据库查询,性能很慢,通过增加超时时间勉强可以访问,但是性能上需要优化。
索引的优点合适的索引,可以大大减小mysql服务器扫描的数据量,避免内存排序和临时表,提高应用程序的查询性能。
索引的类型mysql数据中有多种索引类型,primarykey,unique,normal,但底层存储的数据结构都是BTREE;有些存储引擎还提供hash索引,全文索引。
BTREE是常见的优化要面对的索引结构,都是基于BTREE的讨论。
B-TREE查询数据简单暴力的方式是遍历所有记录;如果数据不重复,就可以通过组织成一颗排序二叉树,通过二分查找算法来查询,大大提高查询性能。
而BTREE是一种更强大的排序树,支持多个分支,高度更低,数据的插入、删除、更新更快。
现代数据库的索引文件和文件系统的文件块都被组织成BTREE。
btree的每个节点都包含有key,data和只想子节点指针。
btree有度的概念d>=1。
假设btree的度为d,则每个内部节点可以有n=[d+1,2d+1)个key,n+1个子节点指针。
树的大高度为h=Logb[(N+1)/2]。
索引和文件系统中,B-TREE的节点常设计成接近一个内存页大小(也是磁盘扇区大小),且树的度非常大。
这样磁盘I/O的次数,就等于树的高度h。
假设b=100,一百万个节点的树,h将只有3层。
即,只有3次磁盘I/O就可以查找完毕,性能非常高。
索引查询建立索引后,合适的查询语句才能大发挥索引的优势。
另外,由于查询优化器可以解析客户端的sql语句,会调整sql的查询语句的条件顺序去匹配合适的索引。