使用 PostgreSQL 优化 Django 中的查询性能:案例研究

最近,我开始开发一项功能,这项功能需要我优化从我编写的代码中触发的数据库查询。这项优化对于确保主页快速加载、提供无延迟的无缝用户体验至关重要。

让我简单介绍一下我正在使用的应用程序。这是一个带有 **PostgreSQL** 数据库的 **Django** 应用程序。我正在开发的功能涉及需要来自多个模型的数据的逻辑,因为该应用程序模块化得很好。

**更加模块化?有问题!**

我们都倾向于遵循已学过的某些编码原则,其中之一就是编写模块化、可重复使用的代码。这种方法对于可维护性和可扩展性非常有用,但在数据库查询方面,有时会导致效率低下。

在 Django 中检查查询执行时间

首先,我想检查从我的代码中触发的查询的性能。我得到了原始 SQL,然后尝试在 **pgAdmin** 中执行它,并使用“EXPLAIN ANALYZE”分析结果。例如,如果您想分析查询,请在其前面加上“EXPLAIN ANALYZE”。

下面是我使用“IN”子句时的样子:

"Unique  (cost=8.19..8.20 rows=1 width=16) (actual 
time=0.045..0.047 rows=1 loops=1)"
"  ->  Sort  (cost=8.19..8.20 rows=1 width=16) (actual 
time=0.045..0.045 rows=1 loops=1)"
"Planning Time: 0.229 ms"
"Execution Time: 0.076 ms"

接下来,我改用“JOIN”,结果如下:

"HashAggregate  (cost=30.07..32.69 rows=262 width=16) (actual 
time=0.148..0.150 rows=1 loops=1)"
"  Batches: 1  Memory Usage: 37kB"
"  ->  Nested Loop  (cost=4.21..28.76 rows=262 width=16) (actual
 time=0.119..0.140 rows=1 loops=1)"
"Planning Time: 0.455 ms"
"Execution Time: 0.222 ms"

**注意到什么了吗?**

是的,**“执行时间”**!

它表明,对于这种特定情况,使用“IN”比使用“JOIN”更快。但是,我们需要考虑一个关键问题:这是否适用于更大的数据集?如果“IN”子句中的数据明显更大,会发生什么?它仍然表现良好吗?答案是**绝对不行**。

性能比较

为了更好地理解 `IN` 和 `JOIN` 之间的权衡,让我们分析一下数据库如何处理这两种方法,尤其是在数据集增长时。

**使用 IN**:

使用“IN”时,数据库本质上是在检查主表中的每一行是否存在于值列表中。虽然对于较小的数据集,这可能很快,但随着“IN”子句中的列表增长,PostgreSQL 必须扫描更大的值集。这会导致执行时间增加,并且可能导致全表扫描,尤其是在子查询或值列表很大的情况下。

**使用 JOIN**:

另一方面,`JOIN` 根据列中的匹配值在表之间建立关系,从而允许数据库使用索引优化流程。虽然对于小数据集,执行时间似乎更差(正如我们在初始测试中看到的那样),但在处理较大的数据集时,`JOIN` 的性能要好得多。

你可以使用什么?

视情况而定!是的,这取决于您的用例和您要解决的问题。您并不总是应该使用 `JOIN` — 对于较小的数据集,`IN` 可能更有效。

因此,请充分了解用例,并从比您更了解用例的人那里获取见解。如果您觉得数据会很大并且会影响性​​能,那么您绝对可以选择“JOIN”。是的,不要忘记在数据库上创建**索引**,以使您的“JOINS”性能更好。

更好地了解索引

在处理大型数据集的连接时,索引至关重要。索引允许 PostgreSQL 根据索引列快速定位行,从而显著提高查询性能。要优化“JOIN”查询,请确保“ON”子句中使用的列以及其他经常查询的列(如 WHERE 和 ORDER BY 子句中的列)。

想要了解有关 PostgreSQL 索引策略的更多信息?请查看有关选择表索引的资源。

我的决定

在评估了 `IN` 和 `JOIN` 方法后,我决定在数据预计会增长的情况下使用 `JOIN`,因为它在处理较大的数据集时能提供更好的性能。但是,在我知道数据量会保持较小的情况下,我选择了 `IN`,因为它可以为较小的数据集提供更快的查询执行速度。

此外,我还对关键列(如 id)实现了索引,以确保`JOIN`查询在应用程序扩展时继续表现良好。

总之,**始终评估您的使用情况,根据数据大小选择最合适的方法,并随时监控您的查询**,以确保在数据扩展时持续优化性能。

祝你编码愉快!💻