您并没有真正说明您为调整 PostgreSQL 实例或查询所做的工作。通过调整和/或以更优化的格式重述查询,可以看到 PostgreSQL 查询的 50 倍加速并不罕见。
就在本周,有人使用 Java 和多个查询编写了一份工作报告,根据它在四个小时内所取得的进展,大约需要一个月才能完成。(它需要访问五个不同的表,每个表都有数亿行。)我使用几个 CTE 和一个窗口函数重写了它,使它在不到十分钟的时间内运行并直接从查询中生成所需的结果。那是 4400 倍的加速。
也许对您的问题的最佳答案与如何在每种产品中执行搜索的技术细节无关,而更多地与您的特定用例的易用性有关。显然,您能够找到使用 Solr 进行搜索的快速方法,而且比 PostgreSQL 更轻松,而且它可能不会归结为更多。
我将包含一个简短的示例,说明如何在 PostgreSQL 中完成对多个条件的文本搜索,以及一些小的调整如何产生很大的性能差异。为了保持快速和简单,我只是将文本形式的战争与和平运行到一个测试数据库中,每个“文档”都是一个文本行。如果必须松散地定义数据,则可以对使用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% 的性能,但在使用 GIN(倒排)索引时,搜索同时包含“女士”和“绅士”的行的速度大约翻了一番,达到 0.053 毫秒(即 53 微秒)。