您并没有真正说明您为调整 PostgreSQL 实例或查询所做的工作。通过调整和/或以更优化的格式重述您的查询,可以看到 PostgreSQL 查询的 50 倍速度提升并不罕见。
就在本周,有人使用 Java 和多个查询编写了一份工作报告,根据该报告在四个小时内所取得的进展,大约需要一个月才能完成。 (它需要访问五个不同的表,每个表都有数亿行。)我使用几个 CTE 和一个窗口函数重写了它,使它在不到十分钟的时间内运行并直接从查询中生成所需的结果。速度提高了 4400 倍。
也许您的问题的最佳答案与如何在每个产品中执行搜索的技术细节无关,而更多地与易用性有关对于您的特定用例。显然,您能够找到使用 Solr 进行搜索的快速方法,而且比 PostgreSQL 更轻松,而且可能仅此而已。
我提供了一个简短的示例,说明如何在 PostgreSQL 中完成对多个条件的文本搜索,以及一些小的调整如何产生很大的性能差异。为了保持快速和简单,我只是将 War and Peace 以文本形式运行到一个测试数据库中,每个“文档”都是一个文本行。如果必须松散定义数据,则可以将类似的技术用于使用hstore 类型或JSON 列的任意字段。如果有单独的列有自己的索引,使用索引的好处往往要大得多。
-- Create the table.
-- In reality, I would probably make tsv NOT NULL,
-- but I'm keeping the example simple...
CREATE TABLE war_and_peace
(
lineno serial PRIMARY KEY,
linetext text NOT NULL,
tsv tsvector
);
-- Load from downloaded data into database.
COPY war_and_peace (linetext)
FROM '/home/kgrittn/Downloads/war-and-peace.txt';
-- "Digest" data to lexemes.
UPDATE war_and_peace
SET tsv = to_tsvector('english', linetext);
-- Index the lexemes using GiST.
-- To use GIN just replace "gist" below with "gin".
CREATE INDEX war_and_peace_tsv
ON war_and_peace
USING gist (tsv);
-- Make sure the database has statistics.
VACUUM ANALYZE war_and_peace;
设置好索引后,我会展示一些搜索,其中包含行数和两种类型索引的计时:
-- Find lines with "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'gentlemen');
84 行,要点:2.006 毫秒,杜松子酒:0.194 毫秒
-- Find lines with "ladies".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'ladies');
184 行,要点:3.549 毫秒,杜松子酒:0.328 毫秒
-- Find lines with "ladies" and "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'ladies & gentlemen');
1 行,要点:0.971 毫秒,杜松子酒:0.104 毫秒
现在,由于 GIN 索引比 GiST 索引快大约 10 倍,您可能想知道为什么有人会使用 GiST 来索引文本数据。答案是 GiST 通常维护起来更快。因此,如果您的文本数据高度不稳定,那么 GiST 索引可能会在整体负载上胜出,而如果您只对搜索时间或以读取为主的工作负载感兴趣,则 GIN 索引会胜出。
如果没有索引,上述查询需要 17.943 毫秒到 23.397 毫秒,因为它们必须扫描整个表并检查每一行是否匹配。
对同时包含“女士”和“绅士”的行进行 GIN 索引搜索比在完全相同的数据库中进行表扫描快 172 倍以上。显然,与本次测试相比,使用更大的文档进行索引的好处会更加显着。
当然,设置是一次性的。使用触发器来维护tsv 列,所做的任何更改都可以立即进行搜索,而无需重新进行任何设置。
对于慢速 PostgreSQL 查询,如果您显示表结构(包括索引)、问题查询以及运行 EXPLAIN ANALYZE 查询的输出,几乎总能有人发现问题并建议如何解决跑得更快。
更新(2016 年 12 月 9 日)
我没有提到我以前获得的时间,但根据日期可能是 9.2 主要版本。我刚刚遇到了这个旧线程,并使用版本 9.6.1 在相同的硬件上再次尝试,看看是否有任何干预性能调整有助于这个示例。仅对一个参数的查询只提高了大约 2% 的性能,但是使用“女士”和“绅士”的行搜索速度大约翻了一番,达到 0.053 毫秒(即 53 微秒) GIN(倒排)索引。