大家好,SQL(结构化查询语言)可以帮助大家从数据库中收集数据,它是专为此而设计的,换句话说,它使用行和列来处理数据,让使用者能够使用SQL查询来操作数据库中的数据。
SQL查询
SQL查询是一系列指令,向数据库发出这些指令以从中收集信息;可以使用这些查询从数据库中收集和操作数据;通过使用它们可以创建报告,进行数据分析等;由于这些查询的形式和长度,执行时间可能会很长,特别是在处理大型数据表时。
SQL查询优化
SQL查询优化的目的是确保你有效地使用资源。通俗地说,它可以减少执行时间,节省成本并提高性能。这对于开发人员和数据分析师来说是一项重要的技能。不仅从数据库返回正确的数据很重要,了解如何有效地做到这一点也很重要。
应该始终问自己:“是否有更好的编写查询的方法?”
让我们更深入地探讨一下这些原因。
资源效率:未经过优化的SQL查询会消耗过多的系统资源,如CPU和内存。这可能会导致整体系统性能下降。优化SQL查询可以确保这些资源得到有效利用。这反过来会导致更好的性能和可扩展性。
减少执行时间:如果查询运行缓慢,这将对用户体验产生负面影响。或者如果有一个正在运行的应用程序,这会导致应用程序性能下降。优化查询可以帮助减少执行时间,提供更快的响应时间和更好的用户体验。
节省成本:优化查询可以减少支持数据库系统所需的硬件和基础设施。这可以在硬件、能源和维护成本方面节约成本。
SQL查询优化技术
这份流程图展示了在优化SQL查询时应遵循的建议步骤。我们将在示例中遵循相同的方法。值得注意的是,优化工具也可以帮助提高查询性能。因此,让我们从众所周知的SQL命令SELECT开始,探索这些技术。
- 使用指定字段的SELECT
当使用SELECT *
时,它将返回表中所有行和所有列,与其扫描整个数据库,不如在SELECT
之后使用特定字段。
在示例中,我们将使用特定的列名替换SELECT *
。正如大家看到的那样,这将减少检索的数据量。因此,查询运行得更快,因为数据库必须获取并提供请求的列,而不是整个表的所有列。这可以在表包含大量列或大量数据行时最大限度地减轻数据库的I/O负担。
以下是优化之前的代码:
SELECT * FROM customer;
以下是输出结果:
总查询运行时间为260毫秒,对此进行改进,为了展示这一点,本文将只选择3个不同列而不是选择全部,你也可以根据项目需要选择所需的列。以下是代码:
SELECT customer_id,
age,
country
FROM customer;
以下是输出结果:
正如你所看到的,通过定义我们要选择的字段,我们不会强制数据库扫描其所有数据,因此运行时间从260毫秒减少到79毫秒。想象一下,如果有数百万或数十亿行,或者有数百列,则会有很大的区别。
- 避免使用SELECT DISTINCT
SELECT DISTINCT用于返回指定列中的唯一值。为此,数据库引擎必须扫描整个表并删除重复的值。在许多情况下,使用类似GROUP BY
的替代方法可以提高性能,因为可以减少处理的数据量。
以下是代码:
SELECT DISTINCT segment
FROM customer;
以下是输出结果:
我们的代码检索了customer
表中segment
列的唯一值,数据库引擎必须处理表中的所有记录,识别重复值并仅返回唯一值。对于大型表格来说,这可能会耗费大量时间和资源。
在替代版本中,以下查询通过使用GROUP BY
子句检索segment
列中的唯一值。GROUP BY
子句根据指定的列对记录进行分组,为每个组返回一条记录。
以下是代码:
SELECT segment
FROM customer
GROUP BY segment;
以下是输出结果:
在本例中,GROUP BY
子句有效地根据segment
列对记录进行分组,从而产生与SELECT DISTINCT
查询相同的输出。
通过避免使用SELECT DISTINCT
并改用GROUP BY
,你可以优化SQL查询并将总查询时间从198毫秒减少到62毫秒,这是超过3倍的速度。
- 避免使用循环
循环可能会导致你的查询速度变慢,因为它们强制数据库一条一条地遍历记录。如果可能的话,使用内置操作和SQL函数,这些函数可以利用数据库引擎的优化并更有效地处理数据。
让我们来定义一个带有循环的自定义函数:
CREATE OR REPLACE FUNCTION sum_ages_with_loop() RETURNS TABLE (country_name TEXT, sum_age INTEGER) AS $$
DECLARE
country_record RECORD;
age_sum INTEGER;
BEGIN
FOR country_record IN SELECT DISTINCT country FROM customer WHERE segment = 'Corporate'
LOOP
SELECT SUM(age) INTO age_sum FROM customer WHERE country = country_record.country AND segment = 'Corporate';
country_name := country_record.country;
sum_age := age_sum;
RETURN NEXT;
END LOOP;
END;
$$ LANGUAGE plpgsql;
上面的代码使用基于循环的方法来计算“Corporate
”客户段中每个国家的年龄总和,它首先检索不同国家的列表,然后使用循环迭代每个国家,计算该国家客户的年龄总和。这种方法可能会很慢和低效,因为它是逐行处理数据。
现在让我们运行这个函数:
SELECT *
FROM sum_ages_with_loop()
以下是输出结果:
使用此方法的运行时间为198毫秒,让我们看一下优化后的SQL代码:
SELECT country,
SUM(age) AS sum_age
FROM customer
WHERE segment = 'Corporate'
GROUP BY country;
以下是输出结果:
通常情况下,使用单个SQL查询的优化版本表现更佳,因为它利用了数据库引擎的优化能力。
为了在我们的第一个代码中获得相同的结果,我们使用了PL/pgSQL函数中的循环,这通常比使用单个SQL查询慢且不够有效,并且迫使编写更多的代码行。