暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何优化MySQL查询的速度和性能

原创 eternity 2022-07-11
499

您可以在阿里云上部署快速、安全、可信的MySQL数据库实例。阿里巴巴拥有先进的基于云的技术网络,其突破性的性能和灵活的计费方式为其100多万付费客户实现了云无国界。

阿里云继续为开源社区做出巨大贡献,并为全球开发者提供了强大的力量。阿里云是2018年MySQL企业贡献奖的获得者,也是MariaDB基金会的白金赞助商。

在本指南中,我们将带您了解在阿里云弹性计算服务(ECS)实例上优化SQL查询和数据库的步骤。这将保证在您的阿里云实例上运行的应用程序和网站的稳定性、可扩展性、可靠性和速度。

先决条件

1.有效的阿里云账户。如果你还没有,你可以注册一个阿里巴巴云,免费试用300美元。

2.运行您最喜欢的操作系统的服务器,可以支持MySQL(例如Ubuntu、Centos、Debian)。

3.MySQL数据库服务器。

4.能够运行root命令的MySQL用户。

1.索引“where”、“order by”和“group by”子句中使用的所有列

除了保证可唯一识别的记录外,索引还允许MySQL服务器更快地从数据库中获取结果。索引在排序记录时也非常有用。

MySQL索引可能会占用更多空间,并降低插入、删除和更新的性能。但是,如果您的表有10行以上,则可以大大减少选择查询的执行时间。

建议使用“最坏情况”样本量的数据测试MySQL查询,以更清楚地了解查询在生产中的行为。

考虑这样一种情况,即从一个包含500行且没有索引的数据库中运行以下SQL查询:

mysql> select customer_id, customer_name from customers where customer_id='140385';

上面的查询将强制MySQL服务器进行完整的表扫描(从开始到结束),以检索我们正在搜索的记录。

幸运的是,MySQL有一个特殊的“EXPLAIN”语句,可以与select、delete、insert、replace和update语句一起使用来分析查询。

在SQL语句之前附加查询后,MySQL将显示优化器提供的有关预期执行计划的信息。

如果我们用explain语句再次运行上述SQL,我们将全面了解MySQL将如何执行查询:

mysql> explain select customer_id, customer_name from customers where customer_id='140385';

+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  500 |    10.00 | Using where |

如您所见,优化器显示了非常重要的信息,可以帮助我们微调数据库表。首先,很明显MySQL将进行全表扫描,因为键列为“NULL”。其次,MySQL服务器明确表示将对数据库中的500行进行完整扫描。

为了优化上述查询,我们可以使用以下语法将索引添加到“customer_id”字段:

mysql> Create index customer_id ON customers (customer_Id);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

如果我们再次运行explain语句,我们将得到以下结果:

mysql> Explain select customer_id, customer_name from customers where customer_id='140385';

+----+-------------+-----------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys | key         | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | customers | NULL       | ref  | customer_id   | customer_id | 13      | const |    1 |   100.00 | NULL  |

从上面的解释输出可以清楚地看出,MySQL服务器将使用我们的索引(customer_Id)来搜索表。您可以清楚地看到,要扫描的行数将为1。虽然我在一个包含500条记录的表中运行了上述查询,但在查询大型数据集(例如,一个包含100万行的表)时,索引可能非常有用。

2、使用Union子句优化Like语句

有时,您可能希望在特定表中的不同字段或列上使用比较运算符“或”运行查询。当where子句中过多使用“or”关键字时,MySQL优化器可能会错误地选择完整表扫描来检索记录。

union子句可以使查询运行得更快,尤其是当您有一个可以优化查询一侧的索引和一个不同的索引来优化另一侧时。

例如,假设您正在运行以下查询,索引为“first_name”和“last_name”:

mysql> select * from students where first_name like  'Ade%'  or last_name like 'Ade%' ;

与下面的查询相比,上面的查询的运行速度要慢得多,下面的查询使用联合运算符合并利用索引的两个独立快速查询的结果。

mysql> select  from students where first_name like  'Ade%'  union all select  from students where last_name like  'Ade%' ;

3.避免使用前导通配符的Like表达式

当查询中有前导通配符时,MySQL无法利用索引。如果我们在students表上举一个例子,这样的搜索将导致MySQL执行完整的表扫描,即使您已经为students表上的“first_name”字段编制了索引。

mysql> select * from students where first_name like  '%Ade'  ;

我们可以使用explain关键字来证明这一点:

mysql> explain select * from students where first_name like  '%Ade'  ;

+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | students | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  500 |    11.11 | Using where |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+

如上所见,MySQL将扫描students表中的所有500行,这将会使得查询速度非常慢。

4、利用MySQL全文搜索

如果您需要使用通配符搜索数据,并且不希望数据库性能不佳,那么应该考虑使用MySQL全文搜索(FTS),因为它比使用通配符的查询快得多。

此外,当您搜索大型数据库时,FTS也可以带来更好的相关结果。

要向students示例表添加全文搜索索引,我们可以使用以下MySQL命令:

mysql>Alter table students ADD FULLTEXT (first_name, last_name);
mysql>Select * from students where match(first_name, last_name) AGAINST ('Ade');

在上面的示例中,我们指定了要与搜索关键字(“Ade”)匹配的列(first_name和last_name)。

如果我们向优化器查询上述查询的执行计划,我们将得到以下结果:

mysql> explain Select * from students where match(first_name, last_name) AGAINST ('Ade');
+----+-------------+----------+------------+----------+---------------+------------+---------+-------+------+----------+-------------------------------+
| id | select_type | table    | partitions | type     | possible_keys | key        | key_len | ref   | rows | filtered | Extra                         |
+----+-------------+----------+------------+----------+---------------+------------+---------+-------+------+----------+-------------------------------+
|  1 | SIMPLE      | students | NULL       | fulltext | first_name    | first_name | 0       | const |    1 |   100.00 | Using where; Ft_hints: sorted |
+----+-------------+----------+------------+----------+---------------+------------+---------+-------+------+----------+-------------------------------+

很明显,即使我们学生的数据库有500行,也只扫描一行,这将加快数据库的速度。

5、优化数据库模式

即使您优化了MySQL查询,并没有找到一个好的数据库结构,但当数据增加时,您的数据库性能仍然会停止。

规范化表格

首先,规范化所有数据库表,即使这会涉及一些权衡。例如,如果要创建两个表来保存客户数据和订单,则应使用客户id在订单表上引用客户,而不是在订单表上重复客户的名称。后者将导致数据库膨胀。

下图指的是一个数据库模式,该模式旨在实现无任何数据冗余的性能。在MySQL数据库规范化中,您应该在整个数据库中只表示一个事实一次。不要在每个表中重复客户名称;相反,只需在其他表中使用customer_Id作为参考。
微信图片_20220711164728.png
此外,始终使用相同的数据类型来存储类似的值,即使它们位于不同的表中,例如,上面的模式使用“INT”数据类型来存储“customer_id”在customers和orders表中。

使用最佳数据类型

MySQL支持不同的数据类型,包括integer、float、double、date、date_time、Varchar和text等。在设计桌子时,你应该知道“越短越好”

例如,如果您正在设计一个可容纳少于100个用户的系统用户表,则应为“user_id”字段使用“TINYINT”数据类型,因为它将容纳从-128到128的所有值。

此外,如果字段需要日期值(例如sale_order_date),则使用date_time数据类型将是理想的,因为在使用SQL检索记录时,您不必运行复杂的函数来将字段转换为日期。

如果希望所有值都是数字,请使用整数值(例如,在student_id或payment_id字段中)。请记住,在计算方面,与Varchar等文本数据类型相比,MySQL可以更好地处理整数值

避免空值

Null表示列中没有任何值。您应该尽可能避免此类值,因为它们可能会损害您的数据库结果。例如,如果要获取数据库中所有订单的总和,但特定订单记录的数量为null,则除非在记录为null时使用MySQL“ifnull”语句返回可选值,否则预期结果可能会出现错误。

在某些情况下,如果记录不必包含特定列/字段的强制值,则可能需要为字段定义默认值。

避免列过多

宽表可能非常昂贵,需要更多的CPU时间来处理。如果可能的话,不要超过100,除非您的业务逻辑特别要求这样做。

与其创建一个宽表,不如考虑将其拆分为逻辑结构。例如,如果您正在创建一个客户表,但您意识到一个客户可以有多个地址,那么最好创建一个单独的表来保存使用“customer_id”字段引用回客户表的客户地址。

优化连接

在连接语句中始终包含更少的表。一条SQL语句的模式设计糟糕,涉及大量连接,可能无法正常工作。经验法则是每个查询最多有十几个连接。

6.MySQL查询缓存

如果你的网站或应用程序执行了很多选择查询(例如WordPress),你应该利用MySQL查询缓存功能。这将在执行读取操作时提高性能。

该技术通过缓存select查询和生成的数据集来工作。这使得查询运行得更快,因为如果执行多次,则会从内存中提取查询。但是,如果应用程序经常更新表,这将使任何缓存的查询和结果集无效。

您可以通过运行以下命令来检查MySQL服务器是否启用了查询缓存:

mysql> show variables like 'have_query_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+
1 row in <b>set</b> (0.00 sec)

设置MySQL服务器查询缓存

您可以通过编辑配置文件(“/etc/MySQL/my.cnf”或“/etc/MySQL/MySQL.conf.d/mysqld.cnf”)来设置MySQL查询缓存值。这将取决于您的MySQL安装。不要设置非常大的查询缓存大小值,因为这会由于缓存开销和锁定而降低MySQL服务器的性能。建议使用几十兆字节的值。

要检查当前值,请使用以下命令:

mysql> show variables like 'query_cache_%' ;
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 16777216 |
| query_cache_type             | OFF      |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+
5 rows in <b>set</b> (0.00 sec)

然后,要调整这些值,请在MySQL配置文件中包括以下内容:

query_cache_type=1
query_cache_size = 10M
query_cache_limit=256k

您可以根据服务器需要调整上述值。

如果默认情况下MySQL缓存已关闭,则指令“query_cache_type=1”将打开MySQL缓存。

默认的“query_cache_size”是1MB,正如我们上面所说的,建议使用大约10MB的值。此外,该值必须超过40KB,否则MySQL服务器将抛出警告,“查询缓存无法设置大小”。

默认的“query_cache_limit”也是1MB。该值控制可以缓存的单个查询结果的数量。

结论

在本指南中,我们向您展示了如何优化托管在阿里云上的MySQL服务器的速度和性能。

我们相信,该指南将使您能够创建更好的查询,并具有结构良好的数据库结构,不仅易于维护,而且还为您的软件应用程序或网站提供了更高的稳定性。

原文标题:How to Optimize MySQL Queries for Speed and Performance
原文作者: Francis Ndungu
原文链接:https://dzone.com/articles/how-to-optimize-mysql-queries-for-speed-and-perfor

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论