Помогите выбрать базу данных NoSQL для проекта - PullRequest
0 голосов
/ 21 марта 2010

Есть таблица:

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 ГБ. Среднее время запроса ~ 0,5 с - это на высоте. И, на мой взгляд, это время будет расти экспоненциально с ростом базы данных.

Должен ли я перенести все это на базу NoSQL, если да, то что?

QUERY:

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 ]

3 голосов
/ 21 марта 2010

1,5 Гбайт - это ничто. Подавать от барана. Создайте структуру данных, которая поможет вам в поиске.

1 голос
/ 21 марта 2010

Я не думаю, что ваша основная проблема здесь - это тип базы данных, которую вы используете, но тот факт, что у вас на самом деле нет «индекса» для поиска: сходство между документами.

Мое предложение состоит в том, чтобы один раз определить, какие 10 документов похожи на каждый из 100.000 doc_ids и кеш результат в новой таблице, подобной этой:

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

, где вы вставите 10 строк в каждый документ, каждый из которых представляет 10 лучших совпадений для него. Вы получите 400 000 строк, к которым вы можете получить прямой доступ по индексу, который должен сократить время поиска до чего-то вроде O (log n) (в зависимости от реализации индекса).

Затем при каждой вставке или удалении документа (или одного из его значений) вы просматриваете документы и соответственно обновляете новую таблицу.

например. когда новый документ вставлен: для каждого из документов уже в таблице

  1. Вы рассчитываете его счет матча и
  2. если оценка выше, чем самая низкая оценка аналогичных документов, кэшированных в новой таблице, которую вы меняете в аналогичном документе, и оценка вновь вставленного документа
0 голосов
/ 21 марта 2010

Если вы получаете такую ​​плохую производительность из PostgreSQL, хорошим началом будет настройка PostgreSQL, вашего запроса и, возможно, вашей модели данных. Такой запрос должен работать намного быстрее на такой маленькой таблице.

0 голосов
/ 21 марта 2010

Во-первых, 0.5s проблема или нет? А вы уже оптимизировали свои запросы, модель данных и настройки конфигурации? Если нет, вы все равно можете получить лучшую производительность. Производительность - это выбор.

Помимо скорости, есть еще и функциональность, которую вы потеряете.

===

Как насчет передачи функции в 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
...