我有一个带有布尔字段索引的表(“test”)。当它是真的时,它使用索引,因此它的加载速度很快但是当它为假时它不会使用它。有什么不对吗?
我在这里解释它的分析:
DB_development=# explain analyze SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 't';
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=22890.67..22890.68 rows=1 width=0) (actual time=1848.655..1848.656 rows=1 loops=1)
-> Index Scan using index_users_on_is_test on users (cost=0.00..22846.51 rows=17665 width=0) (actual time=34.727..1844.081 rows=21457 loops=1)
Index Cond: (is_test = true)
Filter: is_test
Total runtime: 1848.882 ms
(5 rows)
DB_development=# explain analyze SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 'f';
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
Aggregate (cost=84505.74..84505.75 rows=1 width=0) (actual time=9557.632..9557.632 rows=1 loops=1)
-> Seq Scan on users (cost=0.00..84063.72 rows=176807 width=0) (actual time=71.653..9533.595 rows=219531 loops=1)
Filter: (NOT is_test)
Total runtime: 9557.655 ms
(4 rows)
更新
我在这里看到Adding an index on a boolean field它可以忽略索引......我认为这是正确的,因为与测试用户相比,非测试用户实际上相当多。
DB_development=# SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 't';
count
-------
21457
(1 row)
DB_development=# SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 'f';
count
--------
219531
(1 row)
如果是这样的话......我怎么能快速计算呢?
更新
这是创建表和索引:
create_table "users", :force => true do |t|
t.integer "genre_id"
t.integer "country_id"
t.boolean "is_test", :default => false
t.datetime "created_at"
t.datetime "updated_at"
... + 90 more fields (it's my main table)
end
add_index "users", ["country_id"], :name => "index_users_on_country_id"
add_index "users", ["genre_id"], :name => "index_users_on_genre_id"
add_index "users", ["is_test"], :name => "index_users_on_is_test"
... + 17 more indexes
答案 0 :(得分:2)
索引可能无法使用的原因有很多。表太小了。列/值组合不够有选择性。 PostgreSQL“认为”扫描另一种方式会更快。
我在this blogpost中用更多细节和示例描述了它们。
答案 1 :(得分:2)
如果您SET enable_seqscan = off
(仅用于测试目的,请勿在{{1}}中设置或在生产中使用它,因为它会使其他查询大幅减慢)并重新测试,您将会当被迫使用索引时,可能会发现postgresql.conf
情况较慢。
就个人而言,我会删除索引,而是在false
上添加部分索引。
如果这是一种常见模式,我还会考虑将其他频繁使用的索引部分放在(is_test) WHERE (NOT is_test)
上,因为它会大大加快非测试索引的使用速度。
无论如何,如果WHERE (NOT is_test)
案例更快(相当不可能),那么SET enable_seqscan = off
可能会过高。
另外,如果你使用PostgreSQL 9.2,你可能会得到一个更好的真实案例计划;它通常能够使用仅索引扫描来避免扫描表格。如果索引相对于表足够小并且真空运行得足够激烈,它甚至可能仅对错误情况使用仅索引扫描,因为它必须读取这么少的数据。由于你的桌子非常宽(90个字段),这似乎很有可能。所以考虑升级。
答案 2 :(得分:1)
这似乎完全正常......根据行计数,真实值产生大约10%的行;假产生剩余的90%。在后一种情况下,读取整个表比在索引之后来回读取更快。 (它没有足够的选择性,有用。)
答案 3 :(得分:0)
假设您的费用参数设置为默认值,您的表格大约为84063.72-1768页,或640 MB。 (用\ d +验证)
如果需要9秒钟来扫描那么多数据,那么您的服务器会非常过载,或者数据没有被缓存,必须从磁盘读取数据。
您可以通过启用track_io_timing然后使用“explain(analyze,buffers)select”重做查询来获得更好的信息。