SQL查询常见错误与优化

在学习和实践SQL的过程中,难免会犯错误。重要的是要从错误中学习,避免在未来重复同样的错误。本文将介绍通过频繁练习SQL可以避免的一些常见错误以及如何解决这些问题。

数据解释

为了更好地解释,考虑一个销售数据的示例,其中包含代表销售ID、销售金额和销售日期的列。

SalesId:此列代表特定产品的销售ID。

SalesAmount:此列代表该特定产品的销售金额。

SalesDate:此列代表销售发生的日期。

查询执行顺序

执行查询的一个关键点是查询的执行顺序,顺序如下,否则输出可能不是预期的,有时甚至会导致查询错误。

  • 获取数据(FROM, JOIN)
  • 过滤行(WHERE)
  • 分组(GROUP BY)
  • 分组过滤(HAVING)
  • 返回表达式(SELECT)
  • 排序与分页(ORDER BY & LIMIT / OFFSET)

为查询制定最佳计划

为了避免在执行大型查询时遇到麻烦,建议规划并执行命令。最不希望做的是执行一个包含太多嵌套循环的大型查询。

始终养成规划和构建查询格式的习惯,甚至可以使用样本数据测试查询。

选择合适的数据类型

通常,为表中的每一列选择正确的数据类型至关重要。但是,可能会发生溢出,情况可能不会很好看。此外,数据类型转换会增加查询执行时间,因此,如果可能的话,避免在查询中进行数据类型转换是一个好习惯。

避免使用Select *

使用select *查询所有列会提高查询的执行时间,对于大量数据来说是一个昂贵的操作。不使用select *主要是出于性能和安全考虑。

# 错误方式
SELECT * FROM Sales
# 正确方式
SELECT SalesID, SalesAmount FROM Sales

例如,如果想从销售表中获取销售ID,那么应该只选择SalesID列,而不是使用select *选择所有列,这将有助于快速执行查询。上述查询定义了每个列,并且限制了每条记录的大小。

不使用Distinct

Distinct语句通过删除表中的重复行来找到与所选列对应的唯一行。在SQL中,distinct子句是一个耗时的操作,但有一个简单的解决方案。

# 错误方式
SELECT count(distinct SalesID) FROM Sales

可以使用group by代替distinct来使过程更快更平滑。例如,以下查询找到销售详情表中唯一SalesID的计数。

# 正确方式
SELECT count(*) FROM (SELECT SalesID FROM Sales group by SalesID)

预览结果

想象一下,运行一个大型查询,一个计算量大的查询,返回数百万(M)行,最后意识到计算的方式是错误的,这不是预期的输出。

# 错误方式
SELECT SalesID, SalesAmount FROM Sales

为了解决这个问题,使用TOP / LIMIT预览结果,以确保有预期的结果,而不是浪费时间在问题上。

# 正确方式
SELECT TOP 100 SalesID, SalesAmount FROM Sales

不使用Having

通常使用having子句对聚合列应用过滤器,如(sum, min, max等)操作,这些操作是使用group by操作创建的。但有时,使用‘having’子句而不是‘where’子句来过滤表中的数据。

# 错误方式
SELECT count(SalesId), SalesAmount, SalesDate FROM Sales group by SalesDate having EmployeeID = 5

例如,要找到拥有员工ID 5的总销售额,让在结果中使用group by。

# 正确方式
SELECT count(SalesId), SalesAmount, SalesDate FROM Sales where EmployeeID = 5 group by SalesDate

注意Joins

假设销售部门有多个部门,没有员工。让写一个查询来找出特定部门的员工数量。

SELECT s.SalesName, COUNT(*) as EmployeeCnt FROM SalesID s LEFT JOIN dept_emp de ON d.dept_no = de.dept_no GROUP BY d.dept_name

注意,如果没有在Dept_emp上进行左外连接,它将排除没有员工的部门,因为Dept_emp中没有与该dept_no相对应的记录。另一方面,如果不想在结果中包含这些幽灵部门,那么进行左连接将是多余的,浪费的。

使用EXISTS()代替COUNT()

尽管可以使用EXIST()和COUNT()来发现表中是否有特定记录,但使用EXIST()更有效。虽然COUNT()将搜索整个表以提供匹配记录的总数,但EXIST()只会运行直到它在表中找到记录的第一个条目,节省时间和计算能力,使能够优化SQL查询。

当有多个表连接时,执行查询时操作符的优先级非常重要。如果不遵循操作符的优先级,将无法获得预期的输出,因为查询的读取将会不同。例如,想要获取名为“Ana”或“Joey”的每个员工的详细信息,每个员工的薪水至少为10,000美元。

SELECT e.emp_no, e.first_name, e.last_name, s.salary FROM employees e JOIN salaries s ON e.emp_no = s.emp_no WHERE (e.first_name = "Ana" OR e.first_name = "Joey") AND s.salary >= 10000
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485