2012-06-25 8 views
5

Estoy implementando un servicio donde cada usuario debe tener su propia base de datos json/documento. Más allá de dejar que el usuario consulte documentos json por ejemplo, la base de datos también debe admitir transacciones ACID que involucren múltiples documentos, por lo que me he descartado usando Couch/Mongo u otras bases de datos NoSQL (no puedo usar RavenDB ya que debe ejecutarse en sistemas Unix).Necesito una forma eficiente de almacenar/consultar json en una base de datos SQL

Con esto en mente, he estado tratando de encontrar una forma de implementar eso encima de una base de datos SQL. Esto es lo que he ocurrió hasta el momento:

CREATE TABLE documents (
    id INTEGER PRIMARY KEY, 
    doc TEXT 
); 

CREATE TABLE indexes (
    id INTEGER PRIMARY KEY, 
    property TEXT, 
    value TEXT, 
    document_id INTEGER 
) 

Cada usuario tendrá una base de datos con estas dos tablas, y el usuario tendría que declarar qué campos que necesitaba para consultar lo que el sistema podría llenar adecuadamente los 'Índices ' mesa. Entonces, si el usuario 'A' configura su cuenta para habilitar las consultas por 'nombre' y 'edad', cada vez que el usuario inserte un documento que tenga una propiedad 'nombre' o 'edad' el sistema también insertará un registro en los 'índices' tabla, donde la columna 'propiedad' contendría nombre/edad, 'valor' contendría el valor de la propiedad y 'documento_id' apuntaría al documento correspondiente.

Por ejemplo, digamos que el usuario inserta el siguiente documento:

'{"name" : "Foo", "age" 43}' 

Esto daría lugar a un inserto de la mesa 'documentos' y dos insertos más a la mesa 'índices':

INSERT INTO documents (id,doc) VALUES (1, '{"name" : "Foo", "age" 43}'); 
INSERT INTO indexes (property, value, document_id) VALUES ('name', 'foo', 1); 
INSERT INTO indexes (property, value, document_id) VALUES ('age', '43', 1); 

Entonces digamos que el usuario 'A' envió el servicio la siguiente consulta:

'{"name": "Foo", "age": 43}' //(the queries are also json documents). 

esta consulta traducirse a la siguiente SQL:

SELECT doc FROM documents 
WHERE id IN (SELECT document_id FROM indexes 
      WHERE document_id IN (SELECT document_id FROM indexes 
            WHERE property = 'name' AND value = 'Foo') 
      AND property = 'age' AND value = '43') 

Mis preguntas:

  • sabiendo que el usuario puede ser capaz de utilizar un gran número de condiciones en sus consultas (digamos 20-30 y condiciones), lo que haría que la anotación de la subconsulta sea muy alta, ¿cuán eficiente sería la consulta SELECT anterior en la mayoría de los sistemas de bases de datos (postgres, mysql ...)?
  • ¿La solución anterior es viable para una base de datos que finalmente contendrá millones/miles de millones de documentos json?
  • ¿Existe alguna manera mejor de cumplir con mis requisitos?
  • ¿Existe una base de datos de documentos escalable que pueda realizar transacciones ACID que involucren varios documentos y se ejecute en sistemas Unix?
+0

PostgreSQL 9.2 apoyará un tipo de datos JSON y con algunas funciones (por ejemplo, escritas en JavaScript) Lo anterior debería ser posible. Vea aquí un ejemplo: http://people.planetpostgresql.org/andrew/index.php?/archives/249-Using-PLV8-to-index-JSON.html –

+0

ver si CouchDB funcionará para usted: "CouchDB ofrece Semántica ÁCIDA. Hace esto implementando una forma de Control de Simultaneidad de Versiones Múltiples, lo que significa que CouchDB puede manejar un gran volumen de lectores y escritores simultáneos sin conflicto ". –

+0

dato interesante acerca de PostgreSQL, voy a echarle un vistazo, gracias –

Respuesta

5

Su tabla indexes es lo que se conoce como Entity-Attribute-Value.

Las tablas EAV son adecuadas para almacenar información y recuperarla cuando conozca la entidad. (En su caso, la búsqueda de todas las filas indexes cuando se conoce el document_id.)

Pero son terribles al revés: El suministro de combinaciones atributo-valor para buscar una entidad. Que es exactamente lo que tienes en tu consulta final. A medida que más y más entidades comparten las mismas combinaciones de valor de atributo (como name=foo), el rendimiento de la consulta se degrada.

Por lo tanto, para responder a sus primeras dos preguntas:
1. La consulta, como está escrito, requiere n sub-consultas en la búsqueda de n propiedades. Esto escalará muy mal a medida que n crece.
2. A medida que el número de registros crece, se degradará, especialmente con los registros de millones/billones.

En general, si usted lee sobre EAV, gente recomienda encarecidamente rehuir de ella.


Y, peor aún, no hay realmente una buena alternativa dentro de SQL. La forma estándar de optimizar una búsqueda es con un índice, que se puede modelar fácilmente como un conjunto de datos ordenados. Pero usted entonces necesita muchos índices:
- Un índice sobre (fieldX, fieldY, fieldZ) es gran si se busca en las tres columnas.
- Pero es sucks si tiene que buscar en solofieldZ.


Si puede remodelar esto con una mesa tradicional, con un número fijo de columnas, y tienen el espacio para aplicar todas las combinaciones de índice que necesitaría siempre, eso sería que el modelo mas potente.

Si no puede fijar el número de columnas (nueva properties venir a lo largo de todo el tiempo) y/o no tiene espacio para todas las diferentes combinaciones de índice, que parecen ser pegado con EAV. Lo cual funcionará, pero no escala muy bien en términos de resultados 'instantáneos'.

NOTA: Si se queda con EAV, ¿ha probado esta estructura de consulta?

SELECT 
    document_id 
    FROM 
    indexes 
    WHERE 
     (property = 'name' AND value = 'Foo') 
    OR (property = 'age' AND value = '43') 
    GROUP BY 
    document_id 
    HAVING 
    COUNT(*) = 2 

Esto supone que (document_id, property, value) es único. De lo contrario, un documento podría tener ('name', 'foo') dos veces, y así pasar la cláusula COUNT(*).

+0

No creo que la tabla 'índices' es el modelado de datos utilizando el método de 'Entidad-Atributo-Valor', se es solo una manera de indexar 'manualmente' datos sin esquema en la tabla 'documentos'. Olvidé mencionar que las columnas de nombre y valor también se indexarán, ¿no crees que eso hará que las consultas se ejecuten rápidamente? –

+1

@ThiadodeArruda - Desafortunadamente, es exactamente EAV. Tus 'Documentos' son las' Entidades'. Tus 'Propiedades' son los' Atributos'. Y tus 'Valores' son el, bueno, creo que entiendes ese punto. La indexación '(property, value, document_id)' ciertamente mejorará las cosas en comparación con no hacerlo, pero esa es una suposición de trabajo mínima. Todavía tienes todas las dificultades de EAV. Siempre será significativamente más lento que una tabla "tradicional".Y cuantos más registros compartan el mismo valor para cualquier propiedad dada, más lento será. Y cuantas más propiedades busque, más lento aún. – MatBailie

Cuestiones relacionadas