2010-03-21 23 views
0

Il y a une table:Aide à choisir la base de données NoSQL pour le projet

doc_id(integer)-value(integer) 

approximatives 100.000 doc_id et 27.000.000 lignes.

requête majoritaire sur ce tableau - recherche de documents similaires à présent document:

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

De nos jours, nous utilisons PostgreSQL. Poids de la table (avec index) ~ 1,5 GB. Temps de requête moyen ~ 0.5s - il est à la hauteur. Et, à mon avis, cette période va croître exponentielle avec la croissance de la base de données.

Dois-je tout transférer à la base NoSQL, si oui, quoi?

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) 
+0

Veuillez éditer la description pour expliquer quel est le problème réel avec ce que vous avez décrit. Idéalement, quel est le but? le critère pour choisir entre différents systèmes. – bignose

+0

Et qu'est-ce que EXPLAIN a à dire à propos de vos requêtes? Sans un plan de requête, personne ne sait si vous pouvez accélérer les choses. Et sans les index et les paramètres appropriés dans postgresql.conf, la base de données doit être lente. Comme dit ci-dessous, 1,5 Go n'est pas à s'inquiéter, doit être très rapide. Sauf si vous faites les mauvaises choses. –

+0

Quelle est la fonction get_count_by_doc_id? – MkV

Répondre

3

1,5 Gigaoctets est rien. Servez du bélier. Construisez une infrastructure de données qui vous aide à chercher.

0

En premier lieu, est 0.5s un problème ou non? Et avez-vous déjà optimisé vos requêtes, votre datamodel et vos paramètres de configuration? Sinon, vous pouvez toujours obtenir de meilleures performances. La performance est un choix.

Outre la vitesse, il y a aussi la fonctionnalité, c'est ce que vous allez perdre.

===

Qu'en est-il de pousser la fonction à un 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 
+0

Oui, 0.5s est un problème, car attendu dans un proche avenir une augmentation significative de la taille de la table, si le temps pour la requête va croître. Bien sûr, db et requêtes a été optimisé. Il n'y a aucune autre fonctionnalité sur cette table, excepté la recherche de documents similaires. – potapuff

+0

cette requête réduire -> HashAggregate (coût = 0,27..0.28 lignes = 1 largeur = 4) (temps réel = 7.926..11.324 lignes = 1863 boucles = 1) ligne, mais enregistrez seulement quelques millisecondes. – potapuff

0

Si vous obtenez une mauvaise performance de PostgreSQL, un bon début serait de régler PostgreSQL, votre requête et éventuellement votre datamodel. Une requête comme celle-là devrait servir beaucoup plus rapidement sur une si petite table.

1

Je ne pense pas que votre problème principal ici soit le type de base de données que vous utilisez mais le fait que vous n'ayez pas d'index pour ce que vous cherchez: similitude entre les documents.

Ma proposition est de déterminer une fois que les 10 documents semblables à chacun des 100.000 doc_ids et cache le résultat dans une nouvelle table comme ceci:

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

où vous allez insérer 10 lignes par documenter chacun d'eux représentant les 10 meilleurs résultats pour cela. Vous obtiendrez 400.000 lignes auxquelles vous pouvez accéder directement par index, ce qui devrait réduire le temps de recherche à quelque chose comme O (log n) (en fonction de l'implémentation de l'index). Puis, à chaque insertion ou suppression d'un document (ou d'une de ses valeurs), vous parcourez les documents et mettez à jour la nouvelle table en conséquence.

par exemple.lorsqu'un nouveau document est inséré: pour chacun des documents déjà dans la table

  1. vous calculer son score du match et
  2. si le score est plus élevé que le score le plus bas des documents similaires mis en cache dans la nouvelle table vous permutez le similar_doc et le score du document nouvellement inséré