文章851
标签121
分类10

MySQL SQL 查询优化:使用 `USE`, `IGNORE`, `FORCE` 关键字

在 MySQL 中,优化查询性能是提高数据库应用效率的重要部分。USE, IGNORE, 和 FORCE 关键词可以在特定情况下增强查询的灵活性。以下是对这三个关键词的详细介绍及其使用场景。

1. USE 关键字

1.1 概述

USE 关键字用于指定查询所使用的数据库。如果您在一个 MySQL 服务器上有多个数据库,使用 USE 可以确保在正确的数据库上下文中执行查询。

1.2 示例

USE my_database;
SELECT * FROM my_table;

1.3 注意事项

  • 确保在执行查询之前已选择正确的数据库,避免使用错误的表。

2. IGNORE 关键字

2.1 概述

IGNORE 关键字用于在执行某些操作时忽略错误。例如,在插入操作中,如果遇到重复键错误,使用 IGNORE 可以跳过该记录并继续执行。

2.2 示例

INSERT IGNORE INTO my_table (id, name) VALUES (1, 'John');

在这个示例中,如果 id 为 1 的记录已经存在,那么这条插入语句不会抛出错误,而是简单地忽略该操作。

2.3 使用场景

  • 当您希望在插入时避免因重复记录导致的错误时。
  • 在更新操作中,忽略所有不匹配的行。

3. FORCE 关键字

3.1 概述

FORCE 关键字主要用于强制执行某些操作,尤其是在使用 INDEXJOIN 时。例如,可以强制使用某个索引进行查询。

3.2 示例

SELECT * FROM my_table USE INDEX (my_index) WHERE column = 'value';

在这个示例中,USE INDEX 用于强制 MySQL 使用指定的索引 my_index

3.3 使用场景

  • 当查询优化器选择了不理想的执行计划时,可以通过强制使用特定的索引来改善性能。
  • 在某些情况下,强制执行某个表的特定索引可能会提高查询的效率。

4. 综合示例

以下是一个综合示例,展示如何使用这三个关键词:

USE my_database;

INSERT IGNORE INTO my_table (id, name) VALUES (1, 'John');

SELECT * FROM my_table USE INDEX (my_index) WHERE column = 'value';

5. 性能考虑

  • 索引选择:虽然 FORCE 可以帮助优化查询,但过度依赖强制索引可能会影响查询性能,特别是在数据变化较快的情况下。
  • 错误处理:使用 IGNORE 可以避免插入错误,但在某些情况下可能会导致数据丢失,因此应谨慎使用。

Nginx+PHP 环境 499 错误码排查过程小记

过程

0x01

经搜索得知: 哪些情况下会使 Nginx 返回 HTTP CODE 499?

即:「客户端主动关闭连接」

但某一时间段内全部请求均为返回 499,这显然不是所有客户端主动意识上的「关闭」,可能是因为客户端等待超时,自动关闭连接;加上 499 的时间段内包含部分 502,让我不得不怀疑:

PHP 进程「死」了。

0x02

这里的死,不一定是进程结束,也有可能是僵尸,或是陷入死循环,一直在执行某个脚本……

若是逐个检查代码时间来不及(以先解决问题为重),遂排查: Nginx+FastCGI 到底是谁影响超时时间

以及: PHP-max_execution_time 与 fpm.request_terminate_timeout 介绍

0x03

经过上面的调整,大约一周后再次维护服务器。发现情况有所改善—— 499 错误已经由某一时段大量、集中出现变为偶尔发生,且只出现在某几个特定 URI 请求上。

我决定对这几个 URI 对应的接口控制器代码进行检查。由于系统开发时间紧张,代码质量并不高,怀疑是否是程序内有 BUG。

首先查看代码执行时间,约为 1900 ms 左右,简直太慢!经过仔细检查,发现几个严重问题:

  • 查出某表「全部结果」,再「遍历」结果集,查询每条记录「多个字段」的关联模型
  • 未执行 php artisan optimize
  • 未关闭 debug 模式
  • 未调整 log_level

其中,后几条或许无关紧要,但第一条绝对是致命的。

假设一种常见的模型关联场景:

某作者有多篇文章,每篇文章又有多条评论、赞。

由此,若是采用类似:

posts = posts::where('user_id', 1);
foreach(posts as post){
    likes = post->likes;
    comments = post->comments;
}

Laravel 框架内使用类似如上的方式查询,假设作者的文章数为 n,每篇文章关联的模型有 2 个(likes & comments),则执行此控制器,对于数据库的时间复杂度为:O(n*2+1),需要执行如此大量的 SQL 语句!这在后端设计中应该是需要完全避免的,理想情况的时间复杂度应该是 O(n),n 为常量,不受数据规模的影响。

于是修改代码,过程不再详叙,参见 Laravel 官方文档,或: Laravel 学习笔记之模型关联预加载

经过修改,在 Chrome 开发者工具内查看请求 Timing,缩短为原来时间的一半,800ms 左右。

(但此值仍然不够理想,受到视图渲染、操作系统等原因的影响,后期继续优化,不属于本文讨论范围。)

后记

对于部分接口,请求一次需要执行几百条 SQL;那么,回到最开始的问题:

某次请求后,突然引发大量 499。究其根本原因,是否在于因代码的不严谨,引起的 MySQL 死锁呢?

值得研讨。

原文地址 : https://wi1dcard.dev/posts/nginx-php-http-status-499/

">