changer
changer

Reputation: 409

Database design for multiple models?

I have this design.

Table models:

id - primary key
title - varchar(256)

Table model_instances:

id - primary key
model_id - foreign key to app_models.id
title - varchar(256)

Table model_fields:

id - pk
model_id - foreign key to models.id
instance_id - foreign key to model_instances.id
title - name of the field
type - enum [text, checkbox, radio, select, 'etc']

Table model_field_values:

instance_id - forein key model_instance.id
field_id - foreign key to model_fields.id
value - text

Also there can be many values for some field (like for multiple select dropdown)

The problem is: value is always text field, because I want to store different types of data (text, datetime, integer) and this table contains all values for all instances of all models.

For example, if I have 10 models and every model has 1000 instances with 10 fields then model_field_values (at minimum) would contain 100000 rows, if some fields are multiple, then it would contain (120000-150000 rows).

SQL's select using value field would be slow.

Solution 1:

For every model create new model_field_values like:

model.id = 1, model_field_values_1
...
model.id = 10, model_field_values_10

Solution 2:

Because model_fields contains all fields for model, we can create model_field_values like this

model_fields for model.id=1 (by primary key): 1 - text, 2 - integer, 3 - datetime, 4 - smalltext

Fields for model_field_values_1: field_1 text, field_2 integer, field_3 datetime, field_4 varchar(256)

This solution is not good for fields with multiple values, because every multiple value should have another table with link to the row in model_field_values_1, but it is good for searching through database because mysql would use native datatypes in where clauses (not text fields).

May be I miss something? May be there is a better design?

This database would be used in crm-system, where user can create different model with many instances in these models, so I can not preconfigure all tables with all columns.

Upvotes: 0

Views: 142

Answers (1)

O. Jones
O. Jones

Reputation: 108806

Note: 200,000 rows (two tenths of a megarow) is, in the usual operation of MySQL, a medium sized table. It's generally possible to index such a table fairly efficiently. http://use-the-index-luke.com/

That being said, I think I understand your problem. It is, in the jargon of object-oriented design, polymorphism.

You have this model_field_value table, containing

 instance_id
 field_id
 value

Your problem is, the value's native data type is sometimes VARCHAR(255), sometimes DATETIME or maybe TIMESTAMP, and sometimes INT.

And you'll sometimes need to do queries like this one

 SELECT fv.instance_id
   FROM model_field_value fv
  WHERE fv.field_id = something
    AND fv.value >= '2017-01-01'
    AND fv.value <  '2018-01-01'

to find DATETIME values that happened in calendar year 2017. For example.

This is generally a pain in the neck with key/value storage like what you need. For a query like my example to be sargable, you need to be able to put an index on a DATETIME column. But if you don't have such a column, you can't index it. Duh.

Here's a suggestion. Give your table these columns.

 instance_id      INT pk fk
 field_id         INT pk fk
 value            VARCHAR(255)  a text representation of every value.
 value_double     DOUBLE        a numeric representation of every numeric value, or NULL
 value_ts         TIMESTAMP     a timestamp value if possible, or NULL

This table will contain redundant data, and you'll have to be very careful when you're writing it to make sure it's correct. But you will be able to put indexes on the value_ts and value_double columns, so you can make those kinds of queries sargable.

Just an idea.

Upvotes: 0

Related Questions