深入了解 My SQL:数据库优化技巧大揭秘! (My SQL数据库优化)

MySQL 是一种流行的关系型数据库。它被广泛地应用于 Web 应用程序中,也在企业级系统中得到广泛应用。MySQL 提供了多种管理工具,允许管理员对其进行精细的管理和优化。在本文中,我们将深入研究 MySQL 数据库优化的技巧,并探讨如何使用这些技巧来提高数据库性能。

1.使用优化器

MySQL 的优化器是一个用于分析 SQL 查询并产生更优执行计划的软件模块。通过使用优化器,MySQL 可以减少数据库运行时的延迟、提高查询响应速度,并减少服务器的负载。优化器还可以检查数据表、优化查询以及解决索引和表空间问题。因此,使用优化器可以有效地提高 MySQL 的性能和可靠性。

2.使用缓存

MySQL 数据库具有内置缓存功能,称为查询缓存。查询缓存是一种内存存储机制,可以缓存经常访问的查询结果。通过使用查询缓存,MySQL 可以避免重复的查询,并在查询相同数据时提高查询响应速度。

但是,查询缓存也需要适当地配置,以避免缓存过多数据导致内存消耗过大。因此,我们需要使用一些命令来监视和调整查询缓存,以确保其正常运行。

3.优化索引

MySQL 物理组织数据的方式是通过索引。索引的目的是提高查询性能、减少数据检索时的延迟时间,同时减少数据库服务器的负载。因此,我们需要确保表上的索引更佳化。

在优化索引时,我们需要注意以下几点:

– 遵循更佳实践,包括使用合适的数据类型、创建合适的索引类型以及为维护和查询过程中使用的列创建索引。

– 确保索引适用于特定的查询。

– 避免使用过多的索引,因为这可能会影响查询性能和数据库大小。

– 当数据量减少时,应该考虑删除不必要的索引。

4.分析查询

分析 SQL 查询是优化查询的关键步骤之一。分析查询是通过观察查询执行情况以及查询计划来进行的。通过分析查询,我们可以确定哪个查询比较复杂并需要进一步测试,我们还可以确定哪些查询有效,哪些查询需要重新优化。

分析查询需要一些技巧和工具,例如使用 EXPLN 命令,查看查询计划等。通过巧妙地使用这些工具和技巧,我们可以更好地理解查询的执行情况和查询计划,从而更好地优化查询和缩短查询时间。

5.定期维护表

MySQL 数据库需要定期进行维护,以确保其顺利运行。维护任务包括索引重建、优化表、数据备份等。

索引重建是指删除或重新构建索引以提高查询性能。优化表是指对表进行优化,以释放未使用的空间、更好地组织数据、修复表并增加表性能。进入表维护的时间间隔应视表大小、操作类型、数据重要性等多个因素而定,通常每半年或每季度进行一次维护。

6.使用分区

MySQL 支持分区表,这意味着表被分成互相独立的片段,每个片段都存储不同的数据。使用分区表可以提高查询性能、数据维护和备份等方面的效率。

分区的方式和理念有很多,下面是其中的几种:

– 列表分区:根据列的值定义分区。

– 范围分区:根据列值的范围定义分区。

– 散列分区:根据列值的哈希值定义分区。

– 关键值分区:按主键值进行分区。

7.避免使用子查询

子查询是一种查询语言构造,使用子查询会增加查询的响应时间和数据库的负载。因此,我们需要尽可能避免使用子查询。在某些情况下,可以通过重构查询,将复杂的子查询转换为简单的联结语句来减少响应时间和服务器负载。

8.使用 MySQL 的元数据

元数据是关于数据库元素,如表、列、索引和用户等的数据。使用 MySQL 的元数据,我们可以优化查询、分析性能和数据库运行状况。

例如,在查询优化和索引优化中,我们可以使用 MySQL 的元数据来了解表和索引的组织方式、大小和数据分布等信息。这些信息可以帮助我们精细地管理和优化数据库。

MySQL 是一种流行的关系型数据库,它具有强大的优化和管理工具,可用于管理和优化数据库。本文介绍了一些 MySQL 数据库优化的技巧,例如使用优化器、查询缓存、索引优化、查询分析、定期维护表、使用分区、避免使用子查询和使用元数据等。通过学习和应用这些技巧,可以有效地优化 MySQL 数据库并提高其性能。

参考资料:

– MySQL documentation

– MySQL Performance Blog

相关问题拓展阅读:

什么是SQL的查询优化,举例说明

使用SET NOCOUNT ON 选项:

缺省地,每次执行SQL语句时,一个消息会从服务端发给客户端以显示SQL语句影响的行数。这些信息对客户端来说很少有用。通过关闭这个缺省值,你能减少在服务端和客户端的网络流量,帮助全面提升服务器和应用程序的性能。为了关闭存储过程级的这个特点,在每个存储过程的开头

包含“SET NOCOUNT ON”语句。

正确使用UNION和UNION ALL:

许多人没完全理解UNION和UNION SELECT是怎样工作的,因此,结果浪费了大量不必要的SQLServer资源。当使用UNION时,它相当于在结果集上执行SELECT DISTINCT。换句话说,UNION将联合两个相类似的记录集,然后搜索重复的记录并排除。如果这是你的目的,那么使用UNION是正

确的。但如果你使用UNION联合的两个记录集没有重复记录,那么使用UNION会浪费资源,因为它要寻找重复记录,即使你确定它们不存在。

所以如果你知道你要联合的记录集里没有重复,那么你要使用辩含衫UNION ALL,而不是UNION。UNION ALL联合记录集,但不搜索重复记录,这样减少SQLServer资源的使用,从而提升性能。

尽量不用SELECT * :

绝大多数情况下,不要用 * 来代替查询返回的字段列表,用 * 的好处是代码量少、就算是表结构或视图的列发生变化,编写的查询SQL语句也不用变,都返回所有的字段。但数据库服务器在解析时,如果碰到 *,则会先分析表的结构,然后把表的所有字段名再罗列出来。这就增加了

分析的时间。

慎用SELECT DISTINCT:

DISTINCT子句仅在特定功能的时候使用,即从记录集中排除重复记录的时候。这是因为DISTINCT子句先获取结果集然后去重,这样增加SQLServer有用资源的携腔使用。当然,如果你需要去做,那就只有去做了。

当如果你知道SELECT语句将从不返回重复记录,那么使用DISTINCT语句对SQLServer资源不必要的浪费。

少用游标:

任何一种游标都会降低SQLServer性能。有些情况不能避免,大多数情况可以避免。所以如果你的应用程序目前正在使用TSQL游标,看看这些代码是否能够重写以避免它们。如果你需要一行一行的执行操作,考虑下边这些选项中的一个或多个来代替游标的使用:

使用临时表

使用WHILE循环

使用派生表

使用相关子查询

使用CASE语句

使用多个查询

上面每一个都能取代游标并且执行更快。 如果你不能避免使用游标,至少试着提高它们的速度,找出加速游标的方法。

选择最有效率的表名顺序:

SQLSERVER的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被更先处理,在FROM子句中包含多个表的情况下,必须选择记录条数最少的表作为基础表,当SQLSERVER处理多个表时,会运用排序及合并的方式连接它们。首先

,扫描之一个表(FROM子句中最后的那个表)并对记录进行排序;然后扫描第二个表(FROM子句中最后第二个表);最后将所有从第二个表中检索出的记录与之一个表中合适记录进行合并。

例如: 表 TAB1有条记录,表 TAB2 有5条记录,选择TAB2作为基础表 (更好的方法):

select count(*) from TAB1 a, TAB2 b

选择TAB1作为基础表 (不佳的方法):

select count(*) from TAB2 a, TAB1 b

如果有3个以上的表连接查询,老桥那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表。

使用表的别名(Alias):

当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个Column上,这样可以减少解析的时间并减少那些由Column歧义引起的语法错误。

SARG你的WHERE条件:

ARGE来源于”Search Argument”(搜索参数)的首字母拼成的”SARG”,它是指WHERE子句里,列和常量的比较。如果WHERE子句是sargable(可SARG的),这意味着它能利用索引加速查询的完成。如果WHERE子句不是可SARG的,这意味着WHERE子句不能利用索引(或至少部分不能利用),

执行的是全表或索引扫描,这会引起查询的性能下降。

在WHERE子句里不可SARG的搜索条件如”IS NULL”, “”, “!=”, “!>”, “! 50000

AND JOB = ‘MANAGER’

AND

AND JOB = ‘MANAGER’

8.避免困难的正规表达式:

MATCHES和LIKE关键字支持通配符匹配,技术上叫正规表达式。但这种匹配特别耗费时间。例如:

SELECT * FROM customer WHERE zipcode LIKE “98_ _ _”

即使在zipcode字段上建立了索引,在这种情况下也还是采用顺序扫描的方式。如果把语句改为SELECT * FROM customer WHERE zipcode >=”98000″,在执行查询时就会利用索引来查询,显然会大大提高速度。

另外,还要避免非开始的子串。例如语句:

SELECT * FROM customer WHERE zipcode >”80″

在where子句中采用了非开始子串,因而这个语句也不会使用索引。

8.避免对大型表行数据的顺序存取:

在嵌套查询中,对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存取策略,一个嵌套3层的查询,如果每层都查询1000行,那么这个查询就要查询10亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如,两个表:学生表(学号、姓名、年龄……)和选课表(

学号、课程号、成绩)。如果两个表要做连接,就要在“学号”这个连接字段上建立索引。

还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的where子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序操作:

SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008

虽然在customer_num和order_num上建有索引,但是在上面的语句中优化器还是使用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的,所以应该改为如下语句:

SELECT * FROM orders WHERE customer_num=104 AND order_num>1001

UNION ALL

SELECT * FROM orders WHERE order_num=1008

这样就能利用索引路径处理查询。

8.EXISTS和IN的使用:

在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。   在这种情况下,使用EXISTS(或NOT EXISTS)通常将提高查询的效率。在子查询中,NOT IN子句将执行一个内部的排序和合并。无论在哪种情况下,NOT IN都是更低效的,因为它对子查询中的表执行

了一个全表遍历。为了避免使用NOT IN,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS。

8.避免在索引列上使用IS NULL和IS NOT NULL:

避免在索引中使用任何可以为空的列,SQLSERVER将无法使用该索引。对于单列索引,如果列包含空值,索引中将不存在此记录;对于复合索引,如果每个列都为空,索引中同样不存在此记录。如果至少有一个列不为空,则记录存在于索引中。  

  如果唯一性索引建立在表的A列和B列上,并且表中存在一条记录的A,B值为(123,null),SQLSERVER将不接受下一条具有相同A,B值(123,null)的记录插入。  

  如果所有的索引列都为空,SQLSERVER将认为整个键值为空,而空不可能等于空,因此你可以插入1000条具有相同键值的记录,当然它们都是空!因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使SQLSERVER停用该索引。下面的代码将会很低效(索引失效):

SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL

8.避免在索引列上使用计算:

WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描。   例如下面的语句低效 :

SELECT … FROM DEPT WHERE SAL * 12 > 25000

而下面的语句将是高效的:

SELECT … FROM DEPT WHERE SAL > 25000/12

请务必注意,查询中不要对索引列进行处理,如:TRIM,substring,convert等等操作。

8.用WHERE子句替换HAVING子句:

避免使用HAVING子句,HAVING只会在检索出所有记录之后才对结果集进行过滤,这个处理需要排序、统计等操作。如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销。

避免或简化排序:

应当简化或避免对大型表进行重复的排序。当能够利用索引自动以适当的次序产生输出时,优化器就避免了排序的步骤。以下是一些影响因素:

l索引中不包括一个或几个待排序的列;

lgroup by或order by子句中列的次序与索引的次序不一样;

l排序的列来自不同的表。

为了避免不必要的排序,就要正确地增建索引,合理地合并数据库表(尽管有时可能影响表的规范化,但相对于效率的提高是值得的)。如果排序不可避免,那么应当试图简化它,如缩小排序的列的范围等。

10 临时表的使用:

临时表有很多特殊的用途,象用来替代游标,不过它们仍能引起性能问题,如果这个问题能消除,SQLServer将执行得更快。在永久表和临时表的数据行相同的条件下,使用临时表没有永久表快。但有时还必须得使用临时表,如先从存储大量数据的永久表中提取符全条件的存放到临时

表,然后在临时表上执行操作。如果是直接在存储大量数据的永久表上执行操作(如:统计、循环等),其性能将大打折扣。所以,使不使用临时表,何时使用临时表,需要具体情况决定。

11 是否使用视图:

视图更大的用途是处理安全相关的问题,而不是一些懒惰的开发人员用来存储经常使用的查询的方法。例如,如果你需要允许用户访问特定SQLServer的数据,那么你也许可以考虑为用户(或组)创建一个视图,然后给用户访问视图而不是基表的权限。另一方面,在应用程序里,从视图选

择数据没有好的理由,相反,绕过视图直接从需要的表里获取数据。原因是许多视图(当然不是全部)返回比SELECT语句所需更多的数据,增加不必要的开销。

例如,假定有一个视图从两个连接表里返回10列。你想要从视图里使用SELECT语句返回其中7列。实际上发生的情况是基于视图的查询先运行,返回数据,然后你的查询针对这些数据运行。既然你仅需要7列,而不是视图返回的10列,更多不必要的数据被返回。浪费SQLServer的资源。

长久以来,大家在争论是查询视图速度快还是直接查询快,本人也不敢轻易下结论,因此作了多次试验,其结果是:基于视图查询,性能确实不会比直接写查询语句快,对于简单的查询,最多是在同一水平上。

当然,上面的测试是在没有为视图创建索引的情况下,SQLServer2023以上可以为视图创建索引,视图索引与表的索引在作用方式上非常相似。与表一样,视图可以有一个集簇索引(clustered index)和多个非集簇索引。创建视图索引后能够提高视图的性能。

如果视图不包含索引,则数据库中不保存视图返回的结果集。有的时候,我们可能要创建涉及大量记录或必须进行复杂计算的视图,比如要进行聚合分组处理或多重连接操作。如果每次引用这些视图的时候让sql server重新生成结果集,数据库开销将非常大。

12 让事务尽可能的短:

保持TSQL事务尽可能的短。这会帮助减少锁(所有类型的锁)的数量,有助于全面提升SQLServer的性能。如果有经验,你也许要将长事务分成更小的事务组。

13 用存储过程代替直接写查询语句:

存储过程为开发人员提供了很多好处,包括:

n减少网络流量和响应时间,提升应用程序性能。例如,通过网络发送一个存储过程调用,而不是发送500行的TSQL将更快,资源使用更少。当每次执行SQL时,都会执行解析SQL语句、估算索引的利用率、绑定变量、读数据块等等工作。

n存储过程执行计划能够重用,驻留在SQLServer内存的缓存里,减少服务器开销。

n客户端执行请求更有效率。例如,如果应用程序需要插入大量的二进制值到一个image数据列而不使用存储过程,它必须转化二进制为字符串(大小会增加一倍),然后发送给SQLServer。当SQLServer接收到后,它必须把字符串值转回二进制格式。大量的浪费开销。存储过程能

消除这个问题通过将应用程序传给SQLServer的二进制格式作为参数,从而减少开销提升性能。

n存储过程帮助提供代码重用。虽然这些不直接提升应用程序的性能,通过减少代码量和减少调试时间来提升开发人员的效率。

n存储过程能封装逻辑。你能够改变存储过程代码而不影响客户端(假定你保持参数相同也不移除任何结果集的列)。这节约开发人员的时间。

n存储过程为你的数据提供更好的安全性。如果你仅使用存储过程,你可以移除直接对表的SELECT、INSERT、UPDATE和DELETE权限从而强迫开发人员使用存储过程访问数据。这会节约DBA的时间。

n作为首要的常规,所有的TSQL代码都应该通过存储过程调用。

13.1 存储过程名不要以 sp_ 开头:

对这一准则,可能很多人会感觉纳闷,是的,我开始也纳闷过。如果创建的存储过程不是运行在Master数据库里,不要使用以sp_为前缀的名称。这个特别的前缀是为系统存储过程保留的。尽管使用这个前缀不会禁止用户定义的存储过程的运行,但会稍微降低一些执行效率。这是因为

SQLServer在执行以sp_为前缀的任何一个存储过程时缺省地首先试图在Master数据库里寻找,尽管那儿没有,这就浪费了寻找存储过程的时间。如果SQLServer在Master数据库里不能找到存储过程,那么接下来会将存储过程的拥有者作为DBO去解析。如果存储过程在目前的数据库里,那么

它会执行。为了避免不必要的延迟,不要用前缀为sp_命名你的任何一个存储过程。

13.2 存储过程的拥有者要相同:

为了更好的性能,同一个存储过程里调用的所有对象的拥有者都应该相同,DBO更适宜。如果不是那样,即对象名相同而拥有者不同,那么SQLServer必须执行名称判断。当发生这样的情形时,SQLServer不能使用存储过程里在内存里的执行计划,相反,它必须重新编译存储过程,从而

影响性能。当从应用程序里调用存储过程时,使用分隔符名称来调用也是重要的。如:

EXEC dbo.myProcedure

代替:

EXEC myProcedure

这样做有两个原因,其中一个和性能有关。首先,使用完全有分隔符的名称有助于消除那些和你要运行的存储过程有潜在的混淆,有助于禁止BUG和潜在的问题。但更重要的是,这样做SQLServer能更直接的访问存储过程执行计划,而不是轮流访问,从而加速了存储过程的性能。当然性能

提升很小,但如果你的服务器每小时要运行成千上万或更多的存储过程,这些节约的小段时间加起来就很可观了。

14 完整性使用下的约束和触发器:

数据库里不要执行多余的完整性特点。例如,如果你正使用主键和外键约束来强迫引用完整性,则不要添加触发器来实现相同的功能而增加不必要的开销。同样既使用约束又使用默认值或既使用约束又使用规则也会执行多余的工作。

15 在SQL中捕捉异常:

这一条准则应该不能算是优化方面的,只是编写要求。现在SQLServer2023中,新增了BEGIN TRY…END TRY和 BEGIN CATCH…END CATCH二个成对语句,用于捕捉运行时出现的异常。在Oracle中,可用 BEGIN…EXCEPTION…END 语句捕捉异常。

把SQL代码块中加入捕捉异常的语句内,有二个好处:一是可以在SQL语句内部得到异常并作错误处理,如在错误代码块内返回自定义错误信息、ROLBACK等。这样可减少应用程序捕捉异常带来的资源开销;另外一个好处就是可以防止死锁情况的发生,当出现死锁时,SQLServer2023会抛出

异常,我们就可捕捉到。

下面列出一些索引的概念,有助于设计表结构和编写SQL语句:

按照存储规则来分:

l聚集索引:该索引中键值的逻辑顺序决定了表中相应行的物理顺序。因此一个表只能包含一个聚集索引,但该索引可以包含多个列(组合索引)。检索效率比普通索引高,但对数据新增/修改/删除的影响比较大。

l非聚集索引:与聚集索引相对,不影响表中的数据存储顺序,检索效率比聚集索引低,对数据新增/修改/删除的影响很少。

按照维护与管理的角度来分:

l唯一索引:惟一索引可以确保索引列不包含重复的值,可以用多个列,但是索引可以确保索引列中每个值组合都是唯一的。

l主键索引:在数据库关系图中为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型。主键索引要求主键中的每个值是唯一的。当在查询中使用主键索引时,它还允许快速访问数据。

l普通索引:由关键字KEY或INDEX定义的索引,唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件或排序条件中的数据列创建索引。只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如整数类型的数据列)来创建索引。允许有重复的列存在

关于My SQL数据库优化的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » 深入了解 My SQL:数据库优化技巧大揭秘! (My SQL数据库优化)