Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql postgres索引查询运行速度慢于预期_Sql_Postgresql_Indexing - Fatal编程技术网

Sql postgres索引查询运行速度慢于预期

Sql postgres索引查询运行速度慢于预期,sql,postgresql,indexing,Sql,Postgresql,Indexing,我有一个表,有250列和10万行。我在带有IN查询的索引列上选择了3个带有where子句的列。in子句中的ID数为2500,输出限制为1000行,下面是粗略的查询: 从表1中选择col1、col2、col3,其中(1、2、3、4等)中的col4限制为1000 这个查询比我预期的要长很多,~1秒。在一个只有2500个匹配项的索引整数列上,这似乎应该更快?也许我的假设是错误的。以下是解释: 为了简单起见,我并没有将所有2500个ID粘贴到解释中,所以忽略其中只有3个ID的事实。这里有什么我遗漏的吗

我有一个表,有250列和10万行。我在带有IN查询的索引列上选择了3个带有where子句的列。in子句中的ID数为2500,输出限制为1000行,下面是粗略的查询:

从表1中选择col1、col2、col3,其中(1、2、3、4等)中的col4限制为1000

这个查询比我预期的要长很多,~1秒。在一个只有2500个匹配项的索引整数列上,这似乎应该更快?也许我的假设是错误的。以下是解释:


为了简单起见,我并没有将所有2500个ID粘贴到解释中,所以忽略其中只有3个ID的事实。这里有什么我遗漏的吗?

在(…)类型的查询中,您似乎正在突破select x where y的限制。基本上,您有一个非常大的表,其中包含大量的搜索条件

根据索引的类型,我猜您有B+树这种查询效率很低。这些类型的索引在通用范围匹配和DB插入中表现良好,而在单值查找中表现较差。您的查询正在对此索引进行约2500次单值查找

你有几个选择来处理这个

  • 使用散列索引(这些索引在单值查找时性能更好)
  • 通过添加一些基于范围的约束来帮助查询优化器,这样您就可以获取2500个值,找到最小值和最大值,并将其添加到查询中。所以基本上附加x_id>min_val和x_id
  • 如果有多个db后端,以并行模式运行查询,只需将2500个约束分解为100个组,然后一次运行所有查询并收集结果。如果根据约束的值对约束进行分组,效果会更好
第一个选项当然更简单,但它的代价是使插入/删除速度变慢

第二个组不受此影响,您甚至不需要将其限制为一个最小-最大组。可以创建N个具有N个最小和最大约束的组。用不同的分组进行测试,看看什么是有效的


最后一个选项当然是性能最好的。

您的查询相当于:

select col1, col2, col3 
from table1 
where 
    col4 = 1
    OR col4 = 2
    OR col4 = 3
    OR col4 = 4
    ... repeat 2500 times ...
select col1, col2, col3 
from table1 
where col4 = 1

UNION

select col1, col2, col3 
from table1 
where col4 = 2

UNION

select col1, col2, col3 
from table1 
where col4 = 3

... repeat 2500 times ...
这相当于:

select col1, col2, col3 
from table1 
where 
    col4 = 1
    OR col4 = 2
    OR col4 = 3
    OR col4 = 4
    ... repeat 2500 times ...
select col1, col2, col3 
from table1 
where col4 = 1

UNION

select col1, col2, col3 
from table1 
where col4 = 2

UNION

select col1, col2, col3 
from table1 
where col4 = 3

... repeat 2500 times ...
基本上,这意味着在一个包含10M行的表上搜索索引2500次。最重要的是,如果
col4
不是唯一的,那么每个搜索都是一次扫描,可能会返回许多行。然后将2500个中间结果集组合在一起

服务器不知道
in
子句中列出的2500个
ID
没有重复。它不知道它们已经被分类了。所以,它别无选择,只能进行2500次独立索引搜索,记住某个地方的中间结果(比如隐式临时表),然后将它们组合在一起

如果您有一个单独的表
table\u,其中包含2500个
ID
,并且在
ID
上有一个主键或唯一键,那么服务器会知道它们是唯一的,并且会对它们进行排序

您的查询如下所示:

select col1, col2, col3 
from 
    table_with_ids 
    inner join table1 on table_with_ids.id = table1.col4
服务器可能能够更有效地执行这样的
join

我将使用2500个ID的预填充(temp)表测试性能,并将其与原始表进行比较。如果差异显著,您可以进一步调查

实际上,我首先要运行这个简单的查询:

select col1, col2, col3 
from table1 
where 
    col4 = 1
并测量运行所需的时间。再好不过了。因此,你将有一个下限,并清楚地指出你能实现什么和不能实现什么。然后,也许把它改成
,其中col4在(1,2)
中,看看事情是如何变化的


稍微提高性能的另一种方法是,不仅要在
col4
上建立索引,还要在
col4、col1、col2、col3
上建立索引。它仍然是一个索引,但在多个列上。(在SQL Server中,我会在
col4
的索引中“包含”列
col1、col2、col3,而不是索引本身的一部分,以使其更小,但我认为Postgres没有这样的功能)。在这种情况下,服务器应该能够从索引本身检索它需要的所有数据,而无需在主表中进行额外的查找。使其成为所谓的“覆盖”索引。

我建议使用一列(主键)将值存储在临时表中,然后使用
内部联接
或。如果表1的col1、col2、col3和col4上有索引,则由于覆盖索引,将不需要表搜索/扫描。从何处获得2500个值?这是一个查询吗?如果是,请出示。@zedfoxus有一个有效点。请注意:索引应该先在
col4
上,然后是其他列。@VladimirBaranov只有一个索引,它在col4上,其余的都被选中了。@Bohemian-2500个ID在我们代码的这一点上都在内存中,尽管它们来自散列字段上的另一个表,但这在这一点上有点不相关,对吧?所以不幸的是,散列索引并没有像我希望的那样有帮助,但我会尝试一下范围约束。这可能有点困难,因为我们要查询的大多数id的id范围都非常大,并且是随机分布的。在这种情况下,也许你应该看看@Bohemian暗示了什么。根据您如何获得这2500个值,解决方案如下所示。如果您有一列或一组列对所有这些2500个ID进行分组,那么您的查询将更加简单和快速。如果不存在此类列,您可以利用预计算,基本上有一个在插入时计算这样一个值的进程,或者一个cron脚本,该脚本将在表中运行并执行计算并将其存储在表中。因此,我尝试使用unique子句将ID放在另一个表中,然后加入查询,但没有任何帮助。我会考虑NE