Search code examples
performancedatabase-designpostgresqlkey-valueentity-attribute-value

Best-performing method for associating arbitrary key/value pairs with a table row in a Postgres DB?


I have an otherwise perfectly relational data schema in place for my Postgres 8.4 DB, but I need the ability to associate arbitrary key/value pairs with several of my tables, with the assigned keys varying by row. Key/value pairs are user-generated, so I have no way of predicting them ahead of time or wrangling orderly schema changes.

I have the following requirements:

  • Key/value pairs will be read often, written occasionally. Reads must be reasonably fast.
  • No (present) need to query off of the keys or values. (But it might come in handy some day.)

I see the following possible solutions:

  1. The Entity-Attribute-Value pattern/antipattern. Annoying, but the annoyance would be generally offset by my ORM.
  2. Storing key/value pairs as serialized JSON data on a text column. A simple solution, and again the ORM comes in handy, but I can kiss my future self's need for queries good-bye.
  3. Storing key/value pairs in some other NoSQL db--probably a key/value or document store. ORM is no help here. I'll have to manage the separate queries (and looming data integrity issues?) myself.

I'm concerned about query performance, as I hope to have a lot of these some day. I'm also concerned about programmer performance, as I have to build, maintain, and use the darned thing. Is there an obvious best approach here? Or something I've missed?


Solution

  • That's precisely what the hstore datatype is for in PostgreSQL.
    http://www.postgresql.org/docs/current/static/hstore.html

    It's really fast (you can index it) and quite easy to handle. The only drawback is that you can only store character data, but you'd have that problem with the other solutions as well.

    Indexes support "exists" operator, so you can query quite quickly for rows where a certain key is present, or for rows where a specific attribute has a specific value.

    And with 9.0 it got even better because some size restrictions were lifted.