我一直在尝试在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)
我在导入几个CSV文件中的数据后创建了索引。两列都被编入索引.... id是主键。 url上的索引是使用默认值pgAdmin创建的普通btree。
我跑的时候:
SELECT sum(((relpages*8)/1024)) as MB FROM pg_class WHERE reltype=0;
......总大小为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
其他较小的表上还有其他索引,但它们很小(<5MB)....所以我在这里忽略了它们
使用url查询test_table时遇到的麻烦,特别是在搜索中使用通配符时,速度(或缺少速度)。 e.g。
select * from test_table where url like 'orange%' limit 20;
...需要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)
再举一个例子......这次是美国人和.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)
然后我从7GB服务器转到14GB服务器。查询速度并不好。
服务器上的观察
postgresql.conf文件只有一些默认值的更改。请注意,我从以下博文中了解了以下一些建议:http://www.gabrielweinberg.com/blog/2011/05/postgresql.html。
对conf的更改
shared_buffers = 512MB
checkpoint_segments = 10
(我更改了checkpoint_segments,因为我在加载CSV文件时收到了很多警告......虽然生产数据库不会非常密集,所以如果需要可以将其更改回3 ......)
cpu_index_tuple_cost = 0.0005
effective_cache_size = 10GB # recommendation in the blog post was 2GB...
在服务器本身的任务管理器中 - &gt;性能选项卡,以下可能是可以提供帮助的人的相关位:
CPU:很少超过2%(无论运行什么查询...当我导入6GB CSV文件时,它达到11%)
内存:1.5 / 14.0GB(11%)
有关记忆的更多细节:
问题
感谢阅读。
答案 0 :(得分:7)
这些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扫描表而言 比使用索引更便宜。)
话虽如此:
analyze
。当然,给予Postgres充足的记忆力也会增加记忆的可能性,但要记住后面的观点。有关微调的详细信息,请参阅手册和:
http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server
关于架构的最后两个注释:
varchar(300)
和varchar
之间没有指定长度(或text
的唯一区别)就长度而言是一个额外的检查约束。如果你实际上不需要数据来适应这个大小,并且除了习惯之外没有任何理由这样做,你的数据库插入和更新将通过摆脱该约束而更快地运行。答案 1 :(得分:3)
除非您的编码或排序规则是C或POSIX,否则普通的btree索引无法有效地满足锚定的类似查询。您可能必须使用varchar_pattern_ops op类声明btree索引才能受益。
答案 2 :(得分:2)
问题在于,每次查找都会遇到全表扫描(“内存中的索引”并不是真正的问题)。每次运行其中一个查询时,数据库都会访问每一行,这会导致磁盘使用率过高。您可以查看here以获取更多信息(尤其是关于运算符类和索引类型的文档链接)。如果您遵循该建议,您应该能够使前缀查找工作正常,即您匹配“orange%”之类的情况。
全文搜索非常适合更自然的文本搜索,例如书面文档,但是它可能更难以使其适用于URL搜索。几个月前邮件列表中还有this thread,可能会针对您要执行的操作提供更多针对特定领域的信息。
答案 3 :(得分:0)
解释分析select * from test_table where url喜欢'orange%'限制20;
您可能希望对类似查询使用gin / gist索引。应该给你比btree更好的结果 - 我不认为btree支持像查询一样。