你有一个缓慢的 SQL 查询吗?如果是这样,那么您来对地方了。
在本文中,您将了解导致 SQL 查询速度变慢的一系列原因以及如何解决这些问题。
您可以更改一些内容以使查询运行良好。让我们来看看。
检查数据库负载
首先要做的事情之一是检查数据库的繁忙程度。如果数据库目前正在做很多工作,或者在高负载下,那么包括你在内的所有查询都会运行缓慢。
要检查这一点,您可以从以下一些查询开始(这比询问所有开发人员要容易得多)。
Oracle:
SELECT *
FROM v$sql;
SELECT *
FROM v$session;
SQL Server:
SELECT TOP 20
qs.sql_handle,
qs.execution_count,
qs.total_worker_time AS Total_CPU,
total_CPU_inSeconds = --Converted from microseconds
qs.total_worker_time/1000000,
average_CPU_inSeconds = --Converted from microseconds
(qs.total_worker_time/1000000) / qs.execution_count,
qs.total_elapsed_time,
total_elapsed_time_inSeconds = --Converted from microseconds
qs.total_elapsed_time/1000000,
st.text,
qp.query_plan
FROM
sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
CROSS apply sys.dm_exec_query_plan (qs.plan_handle) AS qp
ORDER BY qs.total_worker_time DESC;
MySQL:
SHOW PROCESSLIST;
PostgreSQL:
SELECT *
FROM pg_stat_activity;
你的Table上锁了吗?
有时查询可能需要很长时间,因为它试图访问一个被另一个进程锁定的表。
如果正在更新表,则可能会发生这种情况。有时,如果它被选中,它甚至可能发生!
使用上述查询之一或类似的查询来查找当前在数据库上运行的查询。检查他们是否没有访问您正在使用的表。
考虑临时表
如果您的查询很复杂,可以重写它以使用临时表而不是单个大型查询。
这意味着您需要的部分结果将存储在一个表中,然后您可以在主查询中进行查询。
如果您有一组数据被多次使用或访问,则此策略很有用。您可以将计算结果存储在一个表中并从中查询,而不是每次都计算它。
您可以使用 Create Table As Select,它根据 Select 查询的结果创建一个新表。或者,如果表已经存在,您可以使用 Insert Into Select 将数据添加到表中。
避免多视图
视图是数据库中允许您运行预定义查询的对象。它们可以帮助您简化查询并提高安全性。
但是,如果视图在其他视图上运行,那么您最终可能会在彼此之上运行多个查询。您将查询一个视图,该视图查询另一个视图,该视图查询一个表。这会增加额外的复杂性,并会减慢您的查询速度。
考虑只为您的查询访问一个视图。如果一个查询有多个视图,其中一个视图正在查询另一个视图,请考虑为其创建一个新的专用视图。
创建索引
索引是提高查询性能的一种简单有效的方法。
索引是一个数据库对象,它根据特定列存储表中行的引用。这就像一本书后面的索引。
如果您正在运行查询并且速度很慢,则可以从索引中受益。
作为 Join 子句和 Where 子句的一部分,在列上创建索引通常是最有用的。因此,检查那里使用了哪些列,检查它们是否有索引,如果没有则创建它们。
避免选择 *
SELECT * 是一种显示表中所有列的方法。它比输入所有列要快。
选择所有列并让您的应用程序或报表使用它需要的内容可能很诱人。
但是,选择比您需要的更多的列可能会减慢查询速度,因为数据库需要做额外的工作来检索列。
为避免这种情况,请仅选择您需要的列。
例如,而不是这个:
SELECT *
FROM employee;
尝试这个:
SELECT id, first_name, last_name, salary
FROM employee;
你只会得到你需要的列,没有别的。您的查询也可能执行得更好。
除非必要,否则避免使用函数
函数在 SQL 中很有用。它们可以帮助您将数据转换为您需要的数据。
但是,有时它们会减慢您的查询速度。他们可能需要时间来转换数据,如果您选择大量数据,这真的可以加起来。
在 Where 子句或 Join 子句中使用函数也会减慢查询速度。例如,如果您对大写单词进行过滤,则需要将每行中的值转换为大写才能进行转换:
SELECT id, last_name, salary
FROM employee
WHERE UPPER(first_name) = 'JOHN';
相反,尽量不要在 WHERE 子句中使用函数,并考虑是否需要在其他地方使用它们:
SELECT id, last_name, salary
FROM employee
WHERE first_name = 'John';
避免 NOT IN
有两种方法可以从查询中排除一组数据:NOT IN 和 NOT EXISTS。
在大多数情况下,NOT EXISTS 的性能优于 NOT IN。这是因为使用 NOT IN,需要检查每个值。使用 NOT EXISTS,您将编写一个返回值的查询,并且通常更快。
因此,如果您在查询中使用了任何 NOT IN 关键字,请尝试使用 NOT EXISTS 对其进行测试。
考虑 CTE 性能
CTE 或公用表表达式是一个很棒的功能。它们确实可以通过使它们更易于阅读和理解来帮助改进您的 SQL 查询。
有时它们可以提高您的查询的性能,因为 CTE 只运行一次并在您的主查询中多次使用。
有时它们会减慢查询速度,因为数据库没有正确优化它们。
因此,如果您遇到性能问题,请考虑为您的查询编写 CTE 并测试性能。或者,如果您已经有 CTE,请考虑更新查询以不使用 CTE。
不同的数据库对此的处理方式不同,因此请同时尝试它们,看看哪种效果更好。
仅在需要时使用通配符
通配符有助于查找部分匹配的数据。
但是,它们是昂贵的操作。
搜索列中的所有值以部分匹配某个值可能需要很长时间。
SELECT id, first_name, last_name
FROM employee
WHERE last_name LIKE 'B%';
如果您使用通配符匹配,请考虑它是否真的是您需要的。可以用不同的 WHERE 子句代替吗?您可以查找确切的值并改用 IN 或 EXISTS 子句吗?
我看到需要通配符搜索的一种情况是用户搜索查询。但是,还有其他方法可以使用更新的专业技术来完成用户搜索。
结论
这些改进慢速 SQL 查询的建议可以在大多数情况下提供帮助。了解您的查询试图做什么并避免一些降低 SQL 查询速度的常见问题是提高性能的好方法。
原文标题:How to Fix Slow SQL Queries
原文作者:Ben Brumm
原文链接:https://www.databasestar.com/slow-sql/