10个降低性能的SQL问题及改进措施

server/2024/9/24 10:14:05/

大家好,在编写SQL查询时,很多人会出现一些降低性能的问题。本文将介绍在SQL查询中常出现的一些问题,以及如何避免这些问题以提高性能,示例将使用简单的员工名字和数据。

假设有一个名为Employees的表,其中包含以下数据:

sql">| EmployeeID | Name        | Department | Salary | ExperienceYears |
|------------|-------------|------------|--------|-----------------|
| 1          | Anil Kumar  | IT         | 60000  | 5               |
| 2          | Rani Verma  | HR         | 45000  | 3               |
| 3          | Suresh Gupta| IT         | 75000  | 8               |
| 4          | Meera Patel | Marketing  | 55000  | 4               |
| 5          | Vijay Singh | IT         | 50000  | 2               |

现在来介绍一些常见的SQL问题。

1.缺少索引

忘记在搜索或过滤的列上添加索引,这会导致查询速度变慢。

sql">SELECT * FROM Employees WHERE Department = 'IT';

如果不在Department列上添加索引,数据库就必须扫描整个表才能找到IT部门的员工。

这就要添加索引以加快速度:

sql">CREATE INDEX idx_department ON Employees(Department);

现在搜索Department的速度将会更快,因为数据库确切知道要查找的位置。

2.使用SELECT *而不是特定列

使用SELECT *会获取所有列,即使并不需要它们,这会增加获取数据的时间,尤其是在表中有很多列的情况下。

sql">SELECT * FROM Employees WHERE Salary > 50000;

这个查询获取了所有列(EmployeeID、Name、Department等),但也许只需要NameSalary列。实际使用中,只获取必要的列即可:

sql">SELECT Name, Salary FROM Employees WHERE Salary > 50000;

这样可以减少检索的数据量,并加快查询速度。

3.不使用高效的连接

使用低效的连接可能会降低性能,尤其是在连接之前未正确过滤数据的情况下。假设我们有另一个表Departments

sql">| DepartmentID | Department | ManagerName  |
|--------------|------------|--------------|
| 1            | IT         | Rahul Sharma |
| 2            | HR         | Pooja Nair   |
| 3            | Marketing  | Nikhil Rao   |

现在要连接EmployeesDepartments表:

sql">SELECT * 
FROM Employees 
JOIN Departments ON Employees.Department = Departments.Department;

这个查询连接了所有行,即使我们并不需要所有数据。可以只获取必要的列,并提前应用过滤器:

sql">SELECT Employees.Name, Departments.ManagerName 
FROM Employees 
JOIN Departments ON Employees.Department = Departments.Department
WHERE Employees.Salary > 50000;

在这里,只选择员工和经理的姓名,并对数据进行有效过滤。

4.过度使用子查询

子查询可能很有用,但往往会减慢速度,尤其是当子查询是相关的(即为每一行执行一次)时。

sql">SELECT Name, (SELECT Department FROM Departments WHERE Department = Employees.Department) 
FROM Employees;

这个查询为Employees表中的每一行运行一个子查询,这样速度会很慢。可以使用连接代替:

sql">SELECT Employees.Name, Departments.Department 
FROM Employees 
JOIN Departments ON Employees.Department = Departments.Department;

在这种情况下,使用JOIN的速度更快,因为它可以一次性处理数据。

5.不优化WHERE子句

编写低效的WHERE子句会减慢查询速度,尤其是在列没有索引或使用函数的情况下。

sql">SELECT * FROM Employees WHERE UPPER(Name) = 'ANIL KUMAR';

Name列上使用像UPPER()这样的函数会阻止使用该列上的任何索引,从而使查询变慢。

尽可能避免在WHERE子句中使用函数:

sql">SELECT * FROM Employees WHERE Name = 'Anil Kumar';

这样,查询可以在Name列上使用索引,从而加快查询速度。

6.低效使用通配符

LIKE搜索的开头放置通配符(%)会迫使数据库扫描整个列。

sql">SELECT * FROM Employees WHERE Name LIKE '%Kumar';

这个查询会搜索以“Kumar”结尾的任何名字,这样会妨碍索引的使用。

尽量避免以%开始搜索,示例如下:

sql">SELECT * FROM Employees WHERE Name LIKE 'Anil%';

这个查询查找以“Anil”开头的名字,可以使用索引,因此速度更快。

7.使用大型IN子句

使用包含许多值的大型IN子句可能会使查询速度变慢,因为它会迫使数据库比较每个值。

sql">SELECT * FROM Employees WHERE EmployeeID IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

可以使用JOIN或临时表代替:

sql">CREATE TEMPORARY TABLE tempIDs (EmployeeID INT);
INSERT INTO tempIDs VALUES (1), (2), (3), (4), (5);
SELECT * FROM Employees WHERE EmployeeID IN (SELECT EmployeeID FROM tempIDs);

对于大型数据集来说,这种方法更简洁,速度通常也更快。

8.糟糕的数据库设计

如果数据库表未进行规范化(有效组织),查询可能会因数据重复和不必要的复杂性而变慢。

为了避免这个 问题,要确保表遵循规范化规则,将数据分隔到不同的表中,防止重复冗余。例如,可以将部门数据移动到单独的Departments表中,而不是在Employees表中重复部门名称。

9.检索过多数据而不加限制

忘记使用LIMIT或分页可能会导致性能变慢,尤其是在处理大型数据集时。

sql">SELECT * FROM Employees;

即使只需要前几行,这个查询也会检索Employees表中的所有数据。

可以使用LIMIT只获取一部分数据:

sql">SELECT * FROM Employees LIMIT 10;

这样只会获取前10行,使查询速度更快。

10.不检查查询执行计划

不使用诸如EXPLAIN之类的工具来了解查询是如何执行的,可能会导致错失优化机会。

这就需要始终检查执行计划,查看数据库如何处理查询:

sql">EXPLAIN SELECT * FROM Employees WHERE Department = 'IT';

这有助于确定是否使用了索引,以及查询中是否存在瓶颈。

如果SQL查询没有有效编写,可能会减慢数据库的运行速度。通过避免上述问题,可以优化查询,使数据库运行更快。始终确保使用索引、避免不必要的列,并使用EXPLAIN测试查询,以确保它们尽可能快地运行。


http://www.ppmy.cn/server/121299.html

相关文章

[leetcode刷题]面试经典150题之4删除有序数组中的重复项II(中等)

思路大致跟上一题一样 题目 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外…

互联网应用安全

互联网应用安全 1.端口管控2.Web应用安全3.系统安全4.网络安全5.数据安全6.业务安全7.互联网DMZ区安全管控标准 1.端口管控 首先要做的就是端口管控,即在防火墙上严格限制对外开放的端口。原则上DMZ服务器只允许对外开放80、443端口,而且DMZ服务器不允许…

计算机毕业设计之:基于微信小程序的共享充电桩系统的设计与实现

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

git删除本地+远程提交记录

//撤销本地仓库提交 1.git log 2.git reset --soft 指定commit版本号 git reset --soft "版本号":重置至指定版本的提交。这里我们指定版本号为 ②,从而达到撤销 ①的目的。 参数 soft:保留当前工作区(代码和文…

Golang | Leetcode Golang题解之第430题扁平化多级双向链表

题目: 题解: func dfs(node *Node) (last *Node) {cur : nodefor cur ! nil {next : cur.Next// 如果有子节点,那么首先处理子节点if cur.Child ! nil {childLast : dfs(cur.Child)next cur.Next// 将 node 与 child 相连cur.Next cur.Chi…

vue3中使用nexttick

1、引入 import { nextTick } from vue 2、具体使用,配合异步 setup() {const message ref(Hello!)const changeMessage async newMessage > {message.value newMessageawait nextTick()console.log(Now DOM is updated)}} 3、具体使用,普通 方…

flutter 设置字体大小,适应各种屏幕

起因, 目的: 来源就是客户需求。 从个人角度来说,我讨厌 flutter, 和 java 一样, 都是 臃肿,繁琐,死板. 1. 过程: 根据用户的屏幕尺寸,把子元素大小, 字体的大小,都设置为百分比&…

uniapp使用uview2上传图片功能

官网地址Upload 上传 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 前提&#xff0c;需要下载vuew2插件 <view class"upload"><view class"u-demo-block__content"><view class"u-page__upload-item"&…