1

我目前正在编写一个必须多次执行相同查询的应用程序。该查询有一个(可能很大)数组作为参数,如下所示:

SELECT 
  m.a, SUM(m.b) as b, SUM(m.c) as c, SUM(m.d) as d
FROM table_m m JOIN table_k k ON (k.x IN %s AND k.id = m.y)
WHERE m.b > 0
GROUP BY m.a

我在 Postgresql 9.1 上使用 Psycopg2。对于每个查询,我创建一个新游标并用数字列表作为参数执行()查询(该查询在我的测试转换中执行了大约 5000 次)。输入列表的长度在 1 到 5000 项之间变化。

平均而言,查询的运行时间略低于 50 毫秒,最慢的执行时间约为 500 毫秒。

我对此有两个问题:

  • 我能做些什么来优化这个查询吗?
  • 有什么方法可以准备一次查询并执行多次(或者 Psycopg2 是否在内部执行此操作)?

架构table_k

    Column     |  Type  | Modifiers 
---------------+--------+-----------
 id           | bigint | not null
 x            | bigint | 
Indexes:
    "table_k_pkey" PRIMARY KEY, btree (id)
    "table_k_id_x_idx" btree (id, x)
    "table_k_x_idx" btree (x)

架构table_m

      Column        |            Type             | Modifiers 
---------------------+-----------------------------+-----------
 id                  | bigint                      | not null
 y                   | bigint                      | 
 a                   | bigint                      | 
 b                   | integer                     | 
 c                   | integer                     | 
 d                   | double precision            | 
Indexes:
    "table_m_pkey" PRIMARY KEY, btree (id)
    "table_m_y_idx" hash (y)
    "table_m_a_idx" btree (a)
    "table_m_b_idx" btree (b)

希望这是足够的信息。

4

2 回答 2

1

优化器可能并不完全聪明并且评估的IN次数超出了您的预期。尝试将其移动到子查询中:

SELECT 
  m.a, SUM(m.b) as b, SUM(m.c) as c, SUM(m.d) as d
FROM table_m m 
JOIN 
(
    SELECT *
    FROM table_k
    WHERE x IN %s
) k ON k.id = m.y
WHERE m.b > 0
GROUP BY m.a

IN您也可能首先使用长列表来降低性能。您可以尝试创建一个临时表,插入要搜索的值,然后加入临时表。

于 2013-01-26T11:47:10.043 回答
0
  1. 为了回答您的第一个问题,您确实必须显示EXPLAIN (analyze)最快和最慢查询的输出。我看不到查询现在的样子有什么重要的。

  2. 是的,可以PREPARE查询以供以后执行。引用文档:

准备好的语句是可用于优化性能的服务器端对象。当 PREPARE 语句被执行时,指定的语句被解析、分析和重写。当随后发出 EXECUTE 命令时,计划并执行准备好的语句。这种分工避免了重复的解析分析工作,同时允许执行计划依赖于提供的特定参数值。

请注意(在文档中也提到过),您不会从PREPAREing 小语句中获得太多利润,因为解析、分析和重写步骤比实际执行查询花费的时间要少得多。

此外,如果您的查询由不同的会话执行,您将不会获得性能提升,因为 PostgreSQL 没有基础设施来跨会话共享预先准备好的语句。

如果您经常执行查询并且碰巧以相同的输入执行它们,我建议在您的应用程序或某些专用数据库表中组织结果的缓存。您的数组似乎是缓存查找的完美键。

于 2013-01-30T07:15:06.657 回答