Je suis récemment passé de Postgres à Solr et j'ai vu une accélération de ~ 50x dans nos requêtes. Les requêtes que nous exécutons concernent plusieurs plages et nos données sont des listes de véhicules. Par exemple: "Trouver tous les véhicules avec un kilométrage <50 000, 5 000 $ <prix <10 000 $, marque = Mazda ..."
J'ai créé des indices sur toutes les colonnes pertinentes de Postgres, donc cela devrait être une comparaison assez juste. En regardant le plan de requête dans Postgres bien qu'il n'utilisait encore qu'un seul index, puis en scannant (je suppose parce qu'il ne pouvait pas utiliser tous les différents index).
Si je comprends bien, Postgres et Solr utilisent des structures de données (B-arbres) vaguement similaires, et ils mettent tous les deux en cache des données en mémoire. Je me demande donc d'où vient une telle différence de performances.
Quelles différences d'architecture expliqueraient cela?
Tout d'abord, Solr n'utilise pas d'arbres B. Un index Lucene (la bibliothèque sous-jacente utilisée par Solr) est composé d'un segments en lecture seule. Pour chaque segment, Lucene gère un dictionnaire de termes, qui consiste en la liste des termes qui apparaissent dans le segment, triés lexicographiquement. La recherche d'un terme dans ce dictionnaire de termes se fait à l'aide d'une recherche binaire, donc le coût d'une recherche à un seul terme est O(log(t))
où t est le nombre de termes. Au contraire, l'utilisation de l'index d'un SGBDR standard coûte O(log(d))
où d est le nombre de documents. Lorsque de nombreux documents partagent la même valeur pour un domaine, cela peut être une grande victoire.
De plus, le commettant Lucene Uwe Schindler a ajouté le support de très performant requêtes de plage numérique il y a quelques années. Pour chaque valeur d'un champ numérique , Lucene stocke plusieurs valeurs avec des précisions différentes. Cela permet à Lucene d'exécuter des requêtes de plage très efficacement. Étant donné que votre cas d'utilisation semble exploiter beaucoup les requêtes de plage numérique, cela peut expliquer pourquoi Solr est tellement plus rapide. (Pour plus d'informations, lisez les javadocs qui sont très intéressants et donnez des liens vers des articles de recherche pertinents.)
Mais Solr ne peut le faire que parce qu'il n'a pas toutes les contraintes d'un RDBMS. Par exemple, Solr est très mauvais pour mettre à jour un seul document à la fois (il préfère les mises à jour par lots).
Vous n'avez pas vraiment dit grand-chose sur ce que vous avez fait pour régler votre instance PostgreSQL ou vos requêtes. Il n'est pas rare de voir une vitesse 50 fois plus rapide sur une requête PostgreSQL en ajustant et/ou en reformulant votre requête dans un format qui optimise mieux.
Cette semaine, il y avait un rapport au travail que quelqu'un avait écrit en utilisant Java et plusieurs requêtes d'une manière qui, en fonction de la distance parcourue en quatre heures, allait prendre environ un mois pour terminer. (Il devait frapper cinq tables différentes, chacune avec des centaines de millions de lignes.) Je l'ai réécrite en utilisant plusieurs CTE et une fonction de fenêtre afin qu'elle s'exécute en moins de dix minutes et génère les résultats souhaités directement à partir de la requête C'est une accélération de 4400x.
Peut-être que la meilleure réponse à votre question n'a rien à voir avec les détails techniques de la façon dont les recherches peuvent être effectuées dans chaque produit, mais plus à voir avec facilité d'utilisation pour votre cas d'utilisation particulier. De toute évidence, vous avez pu trouver le moyen rapide de rechercher avec Solr avec moins de problèmes que PostgreSQL, et cela peut ne pas se résumer à autre chose.
J'inclus un court exemple de la façon dont les recherches de texte pour plusieurs critères peuvent être effectuées dans PostgreSQL, et comment quelques petits ajustements peuvent faire une grande différence de performances. Pour rester simple et rapide, je lance simplement Guerre et paix sous forme de texte dans une base de données de test, chaque "document" étant une seule ligne de texte . Des techniques similaires peuvent être utilisées pour des champs arbitraires en utilisant le type hstore
ou les colonnes JSON
, si les données doivent être définies de manière lâche. Lorsqu'il existe des colonnes distinctes avec leurs propres index, les avantages de l'utilisation des index ont tendance à être beaucoup plus importants.
-- 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;
Une fois configuré pour l'indexation, j'affiche quelques recherches avec le nombre de lignes et les horaires avec les deux types d'index:
-- Find lines with "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'gentlemen');
84 lignes, Gist: 2,006 ms, gin: 0,194 ms
-- Find lines with "ladies".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'ladies');
184 lignes, Gist: 3,549 ms, gin: 0,328 ms
-- Find lines with "ladies" and "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'ladies & gentlemen');
1 ligne, Gist: 0,971 ms, gin: 0,104 ms
Maintenant, puisque l'index GIN était environ 10 fois plus rapide que l'index Gist, vous pourriez vous demander pourquoi quelqu'un utiliserait Gist pour indexer les données de texte. La réponse est que Gist est généralement plus rapide à entretenir. Donc, si vos données de texte sont très volatiles, l'index Gist pourrait gagner sur la charge globale, tandis que l'index GIN gagnerait si vous êtes uniquement intéressé par le temps de recherche ou pour une charge de travail principalement en lecture.
Sans l'index, les requêtes ci-dessus prennent de 17,943 ms à 23,397 ms car elles doivent analyser la table entière et rechercher une correspondance sur chaque ligne.
La recherche indexée par GIN pour les lignes contenant à la fois "mesdames" et "messieurs" est plus de 172 fois plus rapide qu'une analyse de table dans exactement la même base de données. De toute évidence, les avantages de l'indexation seraient plus spectaculaires avec des documents plus volumineux que ceux utilisés pour ce test.
La configuration est, bien sûr, une chose unique. Avec un déclencheur pour maintenir la colonne tsv
, toutes les modifications apportées seraient instantanément consultables sans refaire la configuration.
Avec une requête PostgreSQL lente, si vous affichez la structure de la table (y compris les index), la requête problématique et la sortie de l'exécution de EXPLAIN ANALYZE
de votre requête, quelqu'un peut presque toujours identifier le problème et suggérer comment le faire fonctionner plus rapidement.
MISE À JOUR (9 décembre 16)
Je n'ai pas mentionné ce que j'utilisais pour obtenir les horaires précédents, mais en fonction de la date, cela aurait probablement été la version majeure de 9.2. Je viens de tomber sur cet ancien thread et je l'ai réessayé sur le même matériel en utilisant la version 9.6.1, pour voir si l'un des réglages des performances intervenant aide cet exemple. Les requêtes pour un seul argument n'ont augmenté que d'environ 2% dans les performances, mais la recherche de lignes avec à la fois "ladies" et "gentlemen" a doublé de vitesse à 0,053 ms (soit 53 microsecondes) lors de l'utilisation de l'indice GIN (inversé).
Solr est conçu principalement pour la recherche de données, pas pour le stockage. Cela lui permet de supprimer une grande partie des fonctionnalités requises d'un RDMS. Donc, (ou plutôt lucene ) se concentre sur des données purement indexées.
Comme vous l'avez sans doute découvert, Solr permet à la fois de rechercher et de récupérer des données à partir de son index. C'est cette dernière capacité (facultative) qui mène à la question naturelle ... "Puis-je utiliser Solr comme base de données?"
La réponse est un oui qualifié, et je vous renvoie à ce qui suit:
Mon opinion personnelle est que Solr est mieux pensé comme un cache consultable entre mon application et les données maîtrisées dans ma base de données. De cette façon, j'obtiens le meilleur des deux mondes.
Cette plus grande différence est qu'un index Lucene/Solr est comme une base de données à table unique sans aucun support pour les requêtes relationnelles (JOIN). N'oubliez pas qu'un index n'est généralement là que pour prendre en charge la recherche et non pour être la source principale des données. Votre base de données peut donc être dans une "troisième forme normale", mais l'index sera complètement dénormalisé et ne contiendra principalement que les données nécessaires à la recherche.
Une autre raison possible est généralement que les bases de données souffrent de fragmentation interne, elles doivent effectuer trop de tâches d'E/S semi-aléatoires sur des demandes énormes.
Cela signifie, par exemple, compte tenu de l'architecture d'index d'une base de données, la requête conduit aux index qui à leur tour conduisent aux données. Si les données à récupérer sont largement diffusées, le résultat prendra du temps et cela semble être ce qui se passe dans les bases de données.
Solr (Lucene) crée un index inversé où la récupération des données devient plus rapide. Je lire que PostgreSQL a également des fonctionnalités similaires mais je ne sais pas si vous l'avez utilisé.
Les différences de performances que vous avez observées peuvent également être expliquées par "qu'est-ce qui est recherché?", "Quelles sont les requêtes des utilisateurs?"