0

这里有张桌子:

doc_id(integer)-value(integer)

大约 100.000 doc_id 和 27.000.000 行。

此表上的多数查询 - 搜索与当前文档相似的文档:

select 10 documents with maximum of 
     (count common to current document value)/(count ov values in document).

现在我们使用 PostgreSQL。表重量(带索引)~1,5 GB。平均查询时间约 0.5 秒 - 这是最高的。而且,在我看来,这一次将随着数据库的增长而呈指数增长。

我应该将所有这些都转移到 NoSQL 库吗?如果是的话,应该怎么做?

询问:

EXPLAIN ANALYZE
SELECT D.doc_id as doc_id,
  (count(D.doc_crc32) *1.0 / testing.get_count_by_doc_id(D.doc_id))::real as avg_doc 
FROM testing.text_attachment D
WHERE D.doc_id !=29758 -- 29758 - is random id
  AND D.doc_crc32 IN (select testing.get_crc32_rows_by_doc_id(29758)) -- get_crc32... is IMMUTABLE
GROUP BY D.doc_id
ORDER BY avg_doc DESC
LIMIT 10

Limit  (cost=95.23..95.26 rows=10 width=8) (actual time=1849.601..1849.641 rows=10 loops=1)
   ->  Sort  (cost=95.23..95.28 rows=20 width=8) (actual time=1849.597..1849.609 rows=10 loops=1)
         Sort Key: (((((count(d.doc_crc32))::numeric * 1.0) / (testing.get_count_by_doc_id(d.doc_id))::numeric))::real)
         Sort Method:  top-N heapsort  Memory: 25kB
         ->  HashAggregate  (cost=89.30..94.80 rows=20 width=8) (actual time=1211.835..1847.578 rows=876 loops=1)
               ->  Nested Loop  (cost=0.27..89.20 rows=20 width=8) (actual time=7.826..928.234 rows=167771 loops=1)
                     ->  HashAggregate  (cost=0.27..0.28 rows=1 width=4) (actual time=7.789..11.141 rows=1863 loops=1)
                           ->  Result  (cost=0.00..0.26 rows=1 width=0) (actual time=0.130..4.502 rows=1869 loops=1)
                     ->  Index Scan using crc32_idx on text_attachment d  (cost=0.00..88.67 rows=20 width=8) (actual time=0.022..0.236 rows=90 loops=1863)
                           Index Cond: (d.doc_crc32 = (testing.get_crc32_rows_by_doc_id(29758)))
                           Filter: (d.doc_id <> 29758)
 Total runtime: 1849.753 ms
(12 rows)
4

4 回答 4

3

1.5 GB 不算什么。从公羊服务。构建一个可以帮助您搜索的数据结构。

于 2010-03-21T09:20:31.317 回答
1

我不认为您在这里的主要问题是您正在使用的数据库类型,而是您实际上没有针对您正在搜索的内容的“索引”:文档之间的相似性。

我的建议是确定一次与 100.000 个 doc_id 中的每一个相似的 10 个文档,并将结果缓存在一个新表中,如下所示:

doc_id(integer)-similar_doc(integer)-score(integer)

您将在每个文档中插入 10 行,每行代表它的 10 个最佳匹配项。您将获得 400.000 行,您可以通过索引直接访问这些行,这应该会将搜索时间减少到 O(log n) 之类的东西(取决于索引实现)。

然后,在每次插入或删除文档(或其值之一)时,您遍历文档并相应地更新新表。

例如,当插入新文档时:对于表格中已经存在的每个文档

  1. 你计算它的匹配分数和
  2. 如果分数高于缓存在新表中的相似文档的最低分数,则交换相似文档和新插入文档的分数
于 2010-03-21T11:30:41.807 回答
0

首先,0.5sa 是不是问题?您是否已经优化了查询、数据模型和配置设置?如果没有,您仍然可以获得更好的性能。性能是一种选择。

除了速度,还有功能,这就是你会失去的。

===

将函数推送到 JOIN 怎么样:

EXPLAIN ANALYZE
SELECT 
    D.doc_id as doc_id,
    (count(D.doc_crc32) *1.0 / testing.get_count_by_doc_id(D.doc_id))::real as avg_doc 
FROM 
    testing.text_attachment D
        JOIN (SELECT testing.get_crc32_rows_by_doc_id(29758) AS r) AS crc ON D.doc_crc32 = r
WHERE 
    D.doc_id <> 29758
GROUP BY D.doc_id
ORDER BY avg_doc DESC
LIMIT 10
于 2010-03-21T08:00:57.860 回答
0

如果您从 PostgreSQL 中获得如此糟糕的性能,那么一个好的开始是调整 PostgreSQL、您的查询和可能的数据模型。像这样的查询应该在这么小的表上运行得更快。

于 2010-03-21T10:05:39.503 回答