跳到主要内容

优化 MySQL 查询以实现最大速度

第三部分:优化 MySQL 查询和索引

MySQL 是大多数网站和应用程序使用的数据库管理系统。数据工程师依赖 SQL(结构化查询语言)来访问和编辑 MySQL 数据库中的数据。
MySQL 查询充当代码与数据库中海量数据之间的桥梁。MySQL 数据库性能调优能够提升数据检索的速度和效率,因为它直接影响应用程序或网站的整体性能。因此,优化 MySQL 查询以实现最大速度至关重要。

  • 如何优化大数据集的 MySQL 查询
  • MySQL 查询优化技术
  • 总结

如何优化大数据集的 MySQL 查询

大多数系统需要针对 SELECT 操作进行高度优化——例如,一个新闻网站每天执行数百万次查询,而数据则以大批量文本文件的形式到达。因此,插入操作需要在一天中的某些时段达到最佳状态,同时不会明显影响数百万用户访问数据。

MySQL 慢查询日志

假设有一个格式良好的“|”分隔文本文件,我们想将其插入到表中,以下是 PHP 代码示例:

if (!($fp = fopen("datafile.txt","r"))) {               // 打开文件读取
print "\nUnable to open datafile.txt for writing"; // 显示错误
exit(); // 结束程序运行
}

while (!feof($fp)) { // 按行循环读取文件
$sline = fgets($fp, 4096); // 将数据存入变量 $sline
$sline = chop($sline); // 去除换行符
list($eno, $fname, $sname, $telno, $salary) = explode("|", $sline);
// 按“|”分割行,填充各个变量
$db->query("INSERT INTO employee(employee_number, firstname, surname, tel_no, salary) VALUES ($eno, '$fname', '$sname', '$telno', $salary)");
} // 结束循环

这段代码可以运行,但速度非常慢。索引缓冲区会在每次插入后刷新。直到最近,MyISAM 表(MySQL 早期默认存储引擎)不允许在读取时同时插入数据。新格式允许这样做,但前提是表中没有已删除的记录(在高负载系统中极不可能)。因此,每次插入期间整个表都会被锁定。这在低流量网站上尚可,但当每秒有数百或数千个查询时,你会很快发现积压。

:从 MySQL 5.5 版本开始,InnoDB 成为默认存储引擎,支持更好的并发插入和读取。此处提及 MyISAM 为历史情况。

如何加速 MySQL 查询

插入数据

插入数据的最佳方法是使用 MySQL 的 LOAD DATA INFILE 命令。据 MySQL 官方称,这种方法比普通插入快约 20 倍。
语法简单,代码也更简洁:

$db->query("LOAD DATA INFILE 'datafile.txt' INTO TABLE employee (employee_number, firstname, surname, tel_no, salary) FIELDS TERMINATED BY '|'");

LOAD DATA INFILE 的默认设置为:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY ''

如果你像普通插入那样不指定这些子句,且字段顺序不同,则需要指定字段列表。始终指定字段列表是良好实践。如果有人后来向表中添加字段,你就不必回头修正之前所有的 INSERTSELECT 语句。
如果你无法正确使用此方法,请检查文本文件格式——所有使用 LOAD DATA 遇到的问题几乎都由损坏的文本文件引起。每行的每个字段必须正确分隔。
你不一定总是从文本文件插入数据——也许你的应用程序需要持续执行大量独立的插入操作。有些方法可以确保大量用户的查询不会受到严重影响。

  • 第一个是使用 INSERT LOW_PRIORITY。它会等待所有读取操作完成后再执行插入,等待空隙,而不是强行插入。如果你的数据库像高峰时段一样繁忙,可能永远没有空隙,执行 INSERT LOW_PRIORITY 的客户端可能会一直等待。

这两种方法都无法保证数据何时插入,甚至是否插入,因此请谨慎使用。

读取数据

DELETETRUNCATE 的区别不仅在于命令执行速度,还包括其他优势。主要区别如下:

  1. DELETE 命令属于 DML(数据操作语言,Data Manipulation Language),用于根据条件删除表中的特定行。可以删除所有行,也可以使用 WHERE 子句筛选要删除的行。

    语法:

    DELETE FROM 表名  
    WHERE 条件;
  2. TRUNCATEDDL(数据定义语言,Data Definition Language) 命令,用于删除表中的所有行或元组。与 DELETE 命令不同,TRUNCATE 命令不包含 WHERE 子句。TRUNCATE 命令不会记录每个删除数据页的事务日志。使用 TRUNCATE 后无法回滚数据。与 DELETE 命令相比,TRUNCATE 命令速度更快。

    语法:

    TRUNCATE TABLE 表名;

MySQL 查询优化技术

以下是其他可能对你有帮助的 MySQL 查询优化指南:

  • 使用索引优化 MySQL 查询
  • 优化 MySQL 索引以支持查询计算

资源列表:

总结

了解如何优化大数据集的 MySQL 查询技巧。MySQL 查询作为代码与数据库中海量数据之间的桥梁,优化 MySQL 查询对于实现最大速度和效率至关重要。针对大数据集优化 MySQL 查询时,使用 MySQL 的 LOAD DATA INFILE 命令插入数据,在高峰期使用 INSERT LOW_PRIORITY 插入数据,并使用 TRUNCATE TABLE 替代 DELETE FROM 快速清空表数据。