Postgresql 这是在Postgres中创建部分索引的正确方法吗?
我们有一个包含400万条记录的表,对于一个特定的常用用例,我们只对salesforce用户类型为“Standard”的记录感兴趣,400万条记录中只有大约10000条记录。可能存在的其他用户类型有“PowerPartner”、“CSLitePortal”、“CustomerSuccess”、“PowerCustomerSuccess”和“CsnOnly” 所以对于这个用例,我认为创建一个部分索引会更好 因此,我计划创建此部分索引,以加快对用户类型为“Standard”的记录的查询,并防止来自web的请求超时:Postgresql 这是在Postgres中创建部分索引的正确方法吗?,postgresql,indexing,postgresql-9.3,where-in,partial-index,Postgresql,Indexing,Postgresql 9.3,Where In,Partial Index,我们有一个包含400万条记录的表,对于一个特定的常用用例,我们只对salesforce用户类型为“Standard”的记录感兴趣,400万条记录中只有大约10000条记录。可能存在的其他用户类型有“PowerPartner”、“CSLitePortal”、“CustomerSuccess”、“PowerCustomerSuccess”和“CsnOnly” 所以对于这个用例,我认为创建一个部分索引会更好 因此,我计划创建此部分索引,以加快对用户类型为“Standard”的记录的查询,并防止来自we
CREATE INDEX user_type_idx ON user_table(userType)
WHERE userType NOT IN
('PowerPartner', 'CSPLitePortal', 'CustomerSuccess', 'PowerCustomerSuccess', 'CsnOnly');
查找查询将被删除
select * from user_table where userType='Standard';
请确认这是否是创建部分索引的正确方法?这将非常有帮助。要使用索引,必须在编写查询时在查询中使用
WHERE
条件
PostgreSQL具有一定的扣减能力,但它无法推断userType='Standard'
与索引中的条件等效
使用
EXPLAIN
确定是否可以使用索引。要使用索引,必须在编写查询时在查询中使用WHERE
条件
PostgreSQL具有一定的扣减能力,但它无法推断userType='Standard'
与索引中的条件等效
使用
EXPLAIN
了解您的索引是否可以使用。Postgres可以使用该索引,但其使用方式(略)比指定的索引效率低,其中user\u type='Standard'
我创建了一个包含400万行的小测试表,其中10.000行具有用户类型'Standard'
。其他值使用以下脚本随机分布:
create table user_table
(
id serial primary key,
some_date date not null,
user_type text not null,
some_ts timestamp not null,
some_number integer not null,
some_data text,
some_flag boolean
);
insert into user_table (some_date, user_type, some_ts, some_number, some_data, some_flag)
select current_date,
case (random() * 4 + 1)::int
when 1 then 'PowerPartner'
when 2 then 'CSPLitePortal'
when 3 then 'CustomerSuccess'
when 4 then 'PowerCustomerSuccess'
when 5 then 'CsnOnly'
end,
clock_timestamp(),
42,
rpad(md5(random()::text), (random() * 200 + 1)::int, md5(random()::text)),
(random() + 1)::int = 1
from generate_series(1,4e6 - 10000) as t(i)
union all
select current_date,
'Standard',
clock_timestamp(),
42,
rpad(md5(random()::text), (random() * 200 + 1)::int, md5(random()::text)),
(random() + 1)::int = 1
from generate_series(1,10000) as t(i);
(我创建的表格不只是几列,因为规划者的选择也受表格大小和宽度的影响)
第一次测试使用索引NOT IN:
create index ix_not_in on user_table(user_type)
where user_type not in ('PowerPartner', 'CSPLitePortal', 'CustomerSuccess', 'PowerCustomerSuccess', 'CsnOnly');
结果:
查询计划
--------------------------------------------------------------------------------------------------------------------------------
stuff.user_表上的位图堆扫描(成本=139.68..14631.83行=11598宽度=139)(实际时间=1.035..2.171行=10000循环=1)
输出:id、一些日期、用户类型、一些号码、一些数据、一些标志
复查条件:(用户\表格。用户\类型='标准'::文本)
缓冲区:共享命中=262
->ix上的位图索引扫描不在(成本=0.00..136.79行=11598宽度=0)(实际时间=1.007..1.007行=10000循环=1)
索引条件:(user\u table.user\u type='Standard'::text)
缓冲区:共享命中=40
总运行时间:2.506毫秒
(以上是我运行语句大约10次以消除缓存问题后的典型执行时间)
正如您所见,planner使用位图索引扫描,这是一种“有损”扫描,需要额外的步骤来过滤误报
使用以下索引时:
create index ix_standard on user_table(id)
where user_type = 'Standard';
这将导致以下计划:
查询计划
----------------------------------------------------------------------------------------------------------------------------------------
使用stuff.user_表上的ix_标准进行索引扫描(成本=0.29..443.16行=10267宽度=139)(实际时间=0.011..1.498行=10000循环=1)
输出:id、一些日期、用户类型、一些号码、一些数据、一些标志
缓冲区:共享命中=313
总运行时间:1.815毫秒
结论:
您的索引已被使用,但仅针对您感兴趣的类型的索引更有效
运行时并没有太大的不同。我对每个解释执行了大约10次,并且ix_标准
索引的平均值略低于2ms,而ix_非
索引的平均值略高于2ms,因此没有真正的性能差异
但一般来说,随着表大小的增加,索引扫描的伸缩性会比位图索引扫描更好。这基本上是由于“重新检查条件”——特别是如果没有足够的内存来保存位图(对于较大的表)。Postgres可以使用它,但它的使用方式(稍微)比指定
其中用户类型为“标准”的索引效率低
我创建了一个包含400万行的小测试表,其中10.000行具有用户类型'Standard'
。其他值使用以下脚本随机分布:
create table user_table
(
id serial primary key,
some_date date not null,
user_type text not null,
some_ts timestamp not null,
some_number integer not null,
some_data text,
some_flag boolean
);
insert into user_table (some_date, user_type, some_ts, some_number, some_data, some_flag)
select current_date,
case (random() * 4 + 1)::int
when 1 then 'PowerPartner'
when 2 then 'CSPLitePortal'
when 3 then 'CustomerSuccess'
when 4 then 'PowerCustomerSuccess'
when 5 then 'CsnOnly'
end,
clock_timestamp(),
42,
rpad(md5(random()::text), (random() * 200 + 1)::int, md5(random()::text)),
(random() + 1)::int = 1
from generate_series(1,4e6 - 10000) as t(i)
union all
select current_date,
'Standard',
clock_timestamp(),
42,
rpad(md5(random()::text), (random() * 200 + 1)::int, md5(random()::text)),
(random() + 1)::int = 1
from generate_series(1,10000) as t(i);
(我创建的表格不只是几列,因为规划者的选择也受表格大小和宽度的影响)
第一次测试使用索引NOT IN:
create index ix_not_in on user_table(user_type)
where user_type not in ('PowerPartner', 'CSPLitePortal', 'CustomerSuccess', 'PowerCustomerSuccess', 'CsnOnly');
结果:
查询计划
----------------------------------------------------------------------------