优化 SQL 查询

优化 sql 查询

在编写查询时,我们应该始终花时间找到编写查询的最佳方式。

有时,这可能意味着使用表面上看起来速度不快但实际上速度很快的方法。

查询优化对于拥有高效的网站至关重要。

虽然查询优化也适用于报告和分析,但作为 web 服务一部分运行的查询是网站用户最关注的查询。

在本文中,我使用 mysql 测试员工数据库:https://dev.mysql.com/doc/employee/en/

模式

create table `employees` (  `emp_no` int not null,  `birth_date` date not null,  `first_name` varchar(14) not null,  `last_name` varchar(16) not null,  `gender` enum('m','f') not null,  `hire_date` date not null,  primary key (`emp_no`),  key `name` (`first_name`,`last_name`) )
create table `salaries` (  `emp_no` int not null,  `salary` int not null,  `from_date` date not null,  `to_date` date not null,  primary key (`emp_no`,`from_date`),  key `salary` (`emp_no`,`salary`))

薪水表可以多次包含同一员工,每次员工薪水发生变化时,薪水表中都会出现一个新行。

任务

此查询的任务是返回年收入超过 50,000 美元的员工编号、名字、姓氏的唯一列表。

除了选择数据之外,我们还需要确保没有重复的员工。

使用 distinct

select distinct    employees.emp_no,    first_name,    last_namefrom    employees    inner join salaries using (emp_no)where    salary > 50000

一般来说,使用 distinct 表明查询可以写得更好。

distinct 获取所有可能的行,并在查询过程结束时删除不需要的重复行。

distinct 是根据所有选定的行计算的。这可能意味着在某些情况下可能会返回重复的名称。

可能发生这种情况的一个示例是,如果我们包含一个员工的每一行都发生更改的列,例如 salary

select distinct    employees.emp_no,    first_name,    last_name,    salaryfrom    employees    inner join salaries using (emp_no)where    salary > 50000

查询执行计划:

-> table scan on   (cost=241946..245972 rows=321886)   └─> temporary table with deduplication  (cost=241946..241946 rows=321886)      └─> nested loop inner join  (cost=209757 rows=321886)         ├─> filter: (salaries.salary > 50000)  (cost=97097 rows=321886)         │  └─> index scan on salaries using salary  (cost=97097 rows=965756)         └─> single-row index lookup on employees using primary (emp_no=salaries.emp_no)  (cost=0.25 rows=1)

执行计划显示使用了临时表,成本较高。临时表的查询速度通常较慢。有时它们是必要的,但如果您能找到一种不使用临时表的查询方法,通常会更有效。

平均响应时间:745ms

使用 group by

确保唯一用户的常用方法是使用 group by

group by 通常比 distinct 更快。它不需要删除重复项的最后一步来完成查询计划

select    employees.emp_no,    first_name,    last_namefrom    employees    inner join salaries using(emp_no)where    salary > 50000group by    employees.emp_no

查询执行计划:

-> table scan on   (cost=241946..245972 rows=321886)   └─> temporary table with deduplication  (cost=241946..241946 rows=321886)      └─> nested loop inner join  (cost=209757 rows=321886)         ├─> filter: (salaries.salary > 50000)  (cost=97097 rows=321886)         │  └─> index scan on salaries using salary  (cost=97097 rows=965756)         └─> single-row index lookup on employees using primary (emp_no=salaries.emp_no)  (cost=0.25 rows=1)

虽然 group by 比 distinct 稍快,但执行计划是相同的。这种情况下它们之间的区别一般与内部查询优化器、查询缓存等有关。

虽然执行计划非常有用,但它们并不总能为您提供内部发生的全部情况,这会导致可能具有相同执行计划的查询之间存在细微的差异。

平均响应时间:721ms

使用子查询

虽然子查询通常被认为效率较低,但有时它们可​​以减少行数,从而使查询速度更快。

在本例中,我们将使用子查询来查找工资超过 50,000 美元的员工编号

select    employees.emp_no,    first_name,    last_namefrom    employeeswhere    emp_no in(        select            emp_no from salaries        where            salary > 50000)

使用该方法,查询时间显着下降。

查询执行计划:

-> nested loop inner join  (cost=89029 rows=33961)   ├─> remove duplicates from input sorted on salary  (cost=5161 rows=33961)   │  └─> filter: (salaries.salary > 50000)  (cost=5161 rows=33961)   │     └─> index scan on salaries using salary  (cost=5161 rows=965756)   └─> single-row index lookup on employees using primary (emp_no=salaries.emp_no)  (cost=80472 rows=1)

在这里您将看到查询不再使用临时表,而是使用更简单的计划,成本值更低。

这些因素导致响应时间更快。

平均响应时间: 234ms

虽然使用子查询显着提高了查询性能,但我们也许可以通过使用 exists 子句获得更好的结果,这比子查询中使用的 in 语句具有一些优势。

使用存在

使用 exists 时,查询一旦找到匹配项就会提前终止。在这种情况下,一旦找到特定员工,它就会提前终止。

虽然某个员工的工资表中有多行,但如果找到匹配的行,则不需要继续检查该特定员工是否存在,因此它会停止查找该员工并继续寻找下一个员工一个。

select    employees.emp_no,    first_name,    last_namefrom    employeeswhere    exists (        select            1        from            salaries        where            salaries.emp_no = employees.emp_no            and salary > 50000)

我们在此查询中使用 select 1 因为 exists 只返回 true 或 false,而不返回该行包含的内容。

虽然我们可以使用 select emp_noselect *,但返回常量可以使查询的意图更清晰,并且在某些情况下可以更高效。

查询执行计划:

-> nested loop inner join  (cost=89029 rows=33961)   ├─> remove duplicates from input sorted on salary  (cost=5161 rows=33961)   │  └─> filter: (salaries.salary > 50000)  (cost=5161 rows=33961)   │     └─> index scan on salaries using salary  (cost=5161 rows=965756)   └─> single-row index lookup on employees using primary (emp_no=salaries.emp_no)  (cost=80472 rows=1)

虽然此查询计划与子查询查询计划相同,但提前终止可以提高执行时间。

平均响应时间:220ms

概括

独特:745ms
分组依据:721ms
子查询:234ms
存在:220ms

使用子查询并不总是最有效的查询方法,但是,在这种情况下,它可以显着改善您的查询。

虽然仅更改查询可以帮助修复缓慢的查询,但还可以考虑其他优化。

创建更好的索引也可以帮助解决缓慢的查询问题,但是添加索引应该保留在重写查询无法帮助查询提高效率的时候。

对自己的数据尝试不同的查询策略非常重要。虽然 exists 是查询此数据集时最有效的策略,但其他数据集的结果可能有所不同,因此请尝试各种查询,看看哪一个最适合您。

以上就是优化 SQL 查询的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/55087.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
如何解决PHP项目规模测量问题?使用phploc可以!
上一篇 2025年11月9日 19:11:03
如何用 AI 航模制作工具与豆包搭配制作航模?操作指南​
下一篇 2025年11月9日 19:12:35

相关推荐

  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • MySQL数据库不支持中文的解决办法

    接上一篇文章,在解决了mysql+flask环境配置问题之后,往数据库存中文字符串会报1366错误,提示不正确的字符。继而发现默认的mysql采用了latin1字符集,这种编码是不支持中文的。 如果想支持中文的话,需要设置一下mysql字符集。 众所周知utf-8是可以的,gbk也没问题,为了可扩展…

    用户投稿 2026年5月10日
    000
  • Golang使用Protobuf定义接口与消息格式

    Protobuf通过字段编号实现兼容性,新增字段可忽略、删除字段可保留编号,确保新旧版本互操作,支持服务独立演进。 在Golang项目中,利用Protobuf定义接口和消息格式,本质上是为服务间通信构建了一套高效、类型安全且跨语言的契约。它让数据结构清晰可见,RPC调用标准化,极大地简化了分布式系统…

    2026年5月10日
    000
  • HTML文档如何工作?如何编辑HTML格式文件?

    HTML文档如何工作?如何编辑HTML格式文件?HTML文档如何工作?如何编辑HTML格式文件?HTML文档如何工作?如何编辑HTML格式文件?HTML文档如何工作?如何编辑HTML格式文件?

    浏览器解析和渲染html的过程包括:1. 解析html构建dom树;2. 结合css构建渲染树;3. 布局计算元素位置;4. 绘制像素到屏幕。编辑html可使用记事本、vs code、sublime text等文本或代码编辑器,其中vs code因语法高亮、自动补全和插件生态成为主流选择。标准htm…

    2026年5月10日 用户投稿
    000
  • Go语言连接外部MySQL数据库:DSN配置与常见错误解析

    本文详细阐述了go语言使用`go-sql-driver/mysql`驱动连接外部mysql数据库的正确方法。重点介绍了数据源名称(dsn)的规范格式,特别是主机地址部分的配置,以避免常见的“getaddrinfow: the specified class was not found.”等网络解析错…

    2026年5月10日
    000
  • php代码如何操作JSON数据_php代码解析和生成JSON的方法

    答案:PHP中处理JSON需使用json_encode()和json_decode()函数。1、将数组转为JSON字符串时,用json_encode()并检查返回值是否为false;2、解析JSON字符串时,调用json_decode()并设第二参数为true返回数组,false则返回对象;3、处理…

    2026年5月10日
    000
  • 后缀php怎么打开_php文件打开方式与运行环境搭建指南

    要打开PHP文件需根据用途选择方式:查看代码可用文本编辑器或IDE,运行则需服务器环境。推荐新手使用XAMPP、WAMP等集成环境,将文件放入htdocs目录后访问localhost;开发者可利用PHP内置服务器,命令行执行php -S localhost:8000运行;高级用户可手动配置Apach…

    2026年5月10日
    000
  • 解决Python脚本中相对路径文件找不到的常见问题与策略

    本文旨在解决python脚本中因相对路径处理不当导致的文件找不到错误,尤其是在项目迁移后。文章将深入探讨python中相对路径的工作原理、当前工作目录(cwd)的影响,并提供使用`os.getcwd()`诊断问题以及利用`os.path.dirname(__file__)`结合`os.path.jo…

    2026年5月10日
    000
  • Golang如何提升TCP长连接处理效率_Golang TCP长连接处理性能优化实践详解

    答案:通过非阻塞I/O、单Goroutine双工模型、sync.Pool对象复用、TCP_NODELAY优化及高效心跳管理,结合系统调优,可显著提升Golang百万级TCP长连接处理效率。 在高并发网络服务场景中,TCP长连接的处理效率直接影响系统的吞吐能力和资源消耗。Golang凭借其轻量级Gor…

    2026年5月10日
    000
  • C++内存检测工具 Valgrind使用实践指南

    Valgrind是一款主要用于Linux和macOS的内存调试工具,可检测内存泄漏、越界访问、未初始化内存使用等问题,通过memcheck工具结合–leak-check=full、–track-origins=yes等选项进行详细分析,需编译时添加-g选项以支持调试信息,虽然…

    2026年5月10日
    000
  • Go语言:检查预编译库的构建版本与平台信息

    本文详细介绍了如何利用go语言内置的`go tool pack`工具,从预编译的go静态库(`.a`文件)中提取其构建信息,包括go编译器版本、操作系统和cpu架构。当`go build`因库版本不匹配而失败时,此方法能帮助开发者准确诊断问题,确保构建环境与库的兼容性。 在Go语言的开发实践中,我们…

    2026年5月10日
    000
  • PHP动态网页数据库备份恢复_PHP动态网页MySQL数据库备份教程

    答案:PHP动态网页的MySQL数据库备份与恢复需通过定期导出SQL文件并安全存储来保障数据安全,核心方法包括使用mysqldump命令行工具实现高效灵活的自动化备份,利用phpMyAdmin图形化工具进行手动导出导入以降低操作门槛,以及通过PHP脚本调用系统命令将备份过程集成到应用中;恢复时可采用…

    2026年5月10日
    000
  • php登录怎么实现_php用户登录系统完整实现

    <blockquote>PHP用户登录系统的核心是安全验证与会话管理。首先创建POST提交的登录表单,避免敏感信息暴露;后端通过session_start()启动会话,使用trim()和htmlspecialchars()清理输入,防止XSS攻击;利用PDO预处理语句查询数据库,防止SQ…

    用户投稿 2026年5月10日
    000
  • 远程MySQL数据库连接指南:从本地PHP应用访问GCP实例数据库

    本文详细指导如何在本地php应用中连接到google cloud platform (gcp) 虚拟机实例上的远程mysql数据库。教程涵盖了数据库连接参数的配置、使用php pdo建立连接的方法、gcp环境下的网络配置要点,以及常见的安全和故障排除建议,旨在帮助开发者顺利实现跨环境的数据库通信。 …

    2026年5月10日
    000
  • 在PHP中实现MySQL数据插入时避免重复记录的策略

    本文将探讨在php应用中向mysql数据库插入数据时,如何有效避免重复记录的产生。针对当主键或唯一索引字段值已存在的情况,我们将介绍使用`insert ignore`语句的策略,以确保数据完整性并防止不必要的重复插入,从而简化数据管理逻辑。 引言:数据完整性与重复记录问题 在数据库管理中,数据完整性…

    2026年5月10日
    000
  • php实现哪些功能

    PHP是一种通用脚本语言,可用来实现广泛的功能,包括:动态Web开发:生成响应用户请求的动态 веб页面。内容管理系统(CMS):构建允许用户管理网站内容的CMS。电子商务:开发具有购物车、订单处理和支付网关集成的电子商务网站。服务器端编程:编写命令行脚本和工具。文件操作:创建、读取、写入和删除文件…

    2026年5月10日
    000
  • PHP 动态 SQL WHERE 子句构建:避免重复 AND 的策略

    本文探讨了在 php 中动态构建 sql 查询 `where` 子句时常见的“`where and`”语法错误及其解决方案。通过逐步构建条件字符串,确保第一个条件不带 `and`,后续条件正确使用 `and` 连接,从而生成符合 sql 规范的查询语句,提高代码的健壮性和可读性。 动态构建 SQL …

    2026年5月10日
    200
  • PHP中基于用户角色的页面访问控制实践

    本教程详细讲解如何在PHP应用程序中利用会话(Session)机制实现基于用户角色的页面访问控制。通过正确的session_start()调用、用户登录时的角色信息存储,以及在受保护页面进行严格的会话和角色类型检查,确保只有特定用户(如“manager”)才能访问指定页面,从而有效防止未经授权的访问…

    2026年5月10日
    100
  • php数据库触发器应用实例_php数据库自动化任务的处理

    通过MySQL触发器与PHP结合,可在数据变更时自动记录日志、校验数据及同步状态。首先创建user_log表并定义AFTER INSERT/UPDATE/DELETE触发器,记录users表的操作信息;随后使用PHP的PDO执行增删改操作,验证日志生成;接着创建BEFORE INSERT触发器限制非…

    2026年5月10日
    000
  • Python官网函数库的深入学习_Python官网标准库高级用法解析

    掌握Python标准库高级用法需深入functools、itertools、subprocess、pathlib和concurrent.futures模块:1. functools的@lru_cache可缓存递归结果提升性能;2. itertools提供product、groupby和cycle等工…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信