Postgresql:如何确保索引在内存中

col*_*mbo 5 sql postgresql indexing configuration

我一直在尝试在Windows Server 2012上的Azure VM上运行postgres 9.3.我最初在7GB服务器上运行它...我现在在14GB Azure VM上运行它.在尝试解决下面描述的问题时,我增加了一个尺寸.

顺便说一句,我对posgresql很新,所以我只是逐点了解配置选项.此外,虽然我喜欢在Linux上运行它,但我和我的同事根本没有专业知识来解决Linux中出现问题时的问题,因此Windows是我们唯一的选择.

问题描述:

我有一个名为test_table的表; 它目前存储大约9000万行.它将每月增长约3-4百万行.test_table中有2列:

id (bigserial)
url (charachter varying 300)
Run Code Online (Sandbox Code Playgroud)

我从几个CSV文件导入数据创建了索引.两列都被编入索引.... id是主键.url上的索引是使用默认值通过pgAdmin创建的普通btree.

我跑的时候:

SELECT sum(((relpages*8)/1024)) as MB FROM pg_class WHERE reltype=0;
Run Code Online (Sandbox Code Playgroud)

...总大小为5980MB

这里讨论的2个索引的单个大小如下,我通过运行得到它们:

 # SELECT relname, ((relpages*8)/1024) as MB, reltype FROM pg_class WHERE 
  reltype=0 ORDER BY relpages DESC LIMIT 10;


             relname      |  mb  | reltype
----------------------------------+------+--------
 test_url_idx             | 3684 |       0
 test_pk                  | 2161 |       0
Run Code Online (Sandbox Code Playgroud)

其他较小的表上还有其他索引,但它们很小(<5MB)....所以我在这里忽略了它们

使用url查询test_table时遇到的麻烦,特别是在搜索中使用通配符时,速度(或缺少速度).例如

select * from test_table where url like 'orange%' limit 20;
Run Code Online (Sandbox Code Playgroud)

...需要20-40秒才能运行.

对上面的运行说明分析给出了以下内容:

# explain analyze select * from test_table where
   url like 'orange%' limit 20;

          QUERY PLAN
-----------------------------------------------------------------    
 Limit  (cost=0.00..4787.96 rows=20 width=57) 
     (actual time=0.304..1898.583 rows=20 loops=1)
   ->  Seq Scan on test_table  (cost=0.00..2303247.60 rows=9621 width=57)
     (actual time=0.302..1898
    .542 rows=20 loops=1)
     Filter: ((url)::text ~~ 'orange%'::text)
     Rows Removed by Filter: 210286
    Total runtime: 1898.650 ms
  (5 rows)
Run Code Online (Sandbox Code Playgroud)

再举一个例子......这次是美国和.com之间的通配符....

# explain  select * from test_table where url 
   like 'american%.com' limit 50;

QUERY PLAN
-------------------------------------------------------
 Limit  (cost=0.00..11969.90 rows=50 width=57)
  ->  Seq Scan on test_table  (cost=0.00..2303247.60 rows=9621 width=57)
     Filter: ((url)::text ~~ 'american%.com'::text)
    (3 rows)


# explain analyze select * from test_table where url 
    like 'american%.com' limit 50;

QUERY PLAN
-----------------------------------------------------
 Limit  (cost=0.00..11969.90 rows=50 width=57) 
    (actual time=83.470..3035.696 rows=50      loops=1)
    ->  Seq Scan on test_table  (cost=0.00..2303247.60 rows=9621 width=57) 
            (actual time=83.467..303
  5.614 rows=50 loops=1)
     Filter: ((url)::text ~~ 'american%.com'::text)
     Rows Removed by Filter: 276142
 Total runtime: 3035.774 ms
(5 rows)
Run Code Online (Sandbox Code Playgroud)

然后我从7GB到14GB的服务器.查询速度并不好.

对服务器的观察

  • 我可以看到内存使用率从未真正超过2MB.
  • 使用LIKE语句运行查询时,磁盘读取将脱离图表.
  • 匹配id(主键)时查询速度非常好

postgresql.conf文件只有一些默认值的更改.请注意,我从以下博客文章中获取了一些建议:http://www.gabrielweinberg.com/blog/2011/05/postgresql.html.

对conf的更改:

shared_buffers = 512MB  

checkpoint_segments = 10 
Run Code Online (Sandbox Code Playgroud)

(我更改了checkpoint_segments,因为我在加载CSV文件时收到了很多警告......虽然生产数据库不会非常密集,所以如果需要,可以将其更改回3 ...)

cpu_index_tuple_cost = 0.0005       
effective_cache_size = 10GB    # recommendation in the blog post was 2GB...
Run Code Online (Sandbox Code Playgroud)

在服务器本身的任务管理器 - >性能选项卡中,以下可能是可以提供帮助的人的相关位:

CPU:很少超过2%(无论运行什么查询...当我导入6GB CSV文件时,它达到11%)

内存:1.5/14.0GB(11%)

关于记忆的更多细节:

  • 使用中:1.4GB
  • 可用:12.5GB
  • 承诺1.9/16.1 GB
  • 缓存:835MB
  • 分页池:95.2MB
  • 非分页池:71.2 MB

问题

  1. 如何确保索引位于内存中(假设内存不会太大)?这只是我需要的配置调整吗?
  2. 在这里实施我自己的搜索索引(例如Lucene)是一个更好的选择吗?
  3. 即使我可以在内存问题中解决索引,postgres中的全文索引功能是否会显着提高性能?

谢谢阅读.

Den*_*rdy 8

这些seq扫描使您看起来analyze在导入数据后没有在桌面上运行.

http://www.postgresql.org/docs/current/static/sql-analyze.html

在正常操作期间,调度运行vacuum analyze是没有用的,因为autovacuum会定期启动.但是在执行大量写入时(例如在导入期间)这很重要.

在一个稍微相关的说明中,如果您需要在结束时而不是在开始时运行锚定查询,请参阅Pavel的PostgreSQL技巧站点上的这个反向索引提示,例如 like '%.com'

http://postgres.cz/wiki/PostgreSQL_SQL_Tricks_I#section_20


关于你的实际问题,要小心你喜欢的那篇文章中的一些建议充其量是可疑的.改变索引使用的成本通常是可疑的,禁用seq扫描是彻头彻尾的愚蠢.(有时,它便宜SEQ扫描表比ITIS使用索引).

话虽如此:

  1. Postgres主要根据索引的使用频率来缓存索引,如果统计数据表明不应该使用索引,则不会使用索引 - 因此需要analyze在导入之后.当然,为Postgres提供足够的记忆也会增加记忆的可能性,但要记住后面的观点.
  2. 3.全文搜索工作正常.

有关微调的进一步阅读,请参阅手册和:

http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server

关于架构的最后两个注释:

  1. 最后我检查过,bigint(在你的情况下是bigserial)比普通int慢.(这是不久前的,所以现在的64位服务器上的差异现在可以忽略不计了.)除非你预见到实际上你需要超过23亿个条目,所以int很多并占用更少的空间.
  2. 从实现的角度来看,a varchar(300)varchar没有指定长度(或者text就此而言)之间的唯一区别是对长度的额外检查约束.如果你实际上并不需要数据来适应这个大小,而且除了习惯之外没有任何理由这样做,你的数据库插入和更新将通过摆脱该约束来更快地运行.