properties table pattern vs storing all properties in json column [duplicate] - mysql

This question already has answers here:
When can I save JSON or XML data in an SQL Table
(8 answers)
Storing JSON in database vs. having a new column for each key
(10 answers)
Closed 3 years ago.
I'd like some feedback on having all properties a model can have in a properties table accessed via relationship (using laravel relationships) vs storing all properties/settings in the same table but in a json column.
Currently, my application has a propeties table called settings that is also polymorphic in nature so multiple models can store their properties there. This table has columns like
key (string),
value(string),
type (string) - tells if the value is of string, integer, boolean, json type
so that I do not send strings to javascript frontend, but instead I can send string, integer, boolean native types for better handling of types in frontend. I do this conversion before I send the properties to the frontend using php function that cast string values to int, boolean, json or string, depending on the type.
This means if a model has 40 properties, all get stored in its own row, so creating one model leads to creating 40 rows that store all properties it may have.
Now the above approach vs approach where I just have a single json column, we can call it settings and I dump all these 40 properties there.
What do I win with json column approach? I shave off a table and I shave off an extra relationship that I need to load on this model each time I do some queries. I also shave off having to each time I get properties cast them to integer, boolean, json or string. (remember the type column above) To keep in mind these properties do not need to be searchable, I need them only for reading from them. I will never use them in queries to return posts based on these properties.
Which one is a better idea to use, I'm building a CMS btw you can see it in action here:
https://www.youtube.com/watch?v=pCjZpwH88Z0

As long as you don't try to use the properties for searching or sorting, there's not much difference.
As you said, putting a JSON column in your model table allows you to avoid a JOIN to the properties table.
I think your properties table actually needs to have one more column, to name the property. So it should be:
key (string),
property (string),
value(string),
type (string) - tells if the value is of string, integer, boolean, json type
The downsides are pretty similar for both solutions.
Queries will be more complex with either solution, compared to querying normal columns.
Storing non-string values as strings is inefficient. It takes more space to store a numeric or datetime value as a string than as a native data type.
You can't apply constraints to the properties. No way to make a property mandatory (you would use NOT NULL for a normal column). No way to enforce uniqueness or foreign key references.
There's one case I can think of that gives JSON an advantage. If one of your custom properties is itself multi-valued, there's a straightforward way to represent this in JSON: as an array within your JSON document. But if you try to use a property table, do you store multiple rows for the one property? Or serialize the set of values into an array on one row? Both solutions feel pretty janky.
Because the "schemaless properties" pattern breaks rules of relational database design anyway, there's not much you can do to "do it right." You're choosing the lesser of two evils, so you can feel free to use the solution that makes your code more convenient.

Related

How to order by a DC2Type:json_array subfield

I'm working in a existing application and I'm asked to order by a child field of a DC2Type:json_array field in Symfony. Normally I would add the field as a column in the table. In this case this is not possible.
We have a JsonSerializable invoice entity with a normal date attribute. But also a data attribute which contains the due_date. I whould like to order by data[due_date] in a Symfony query. Is this at all possible?
tl;dr: No, not really.
According to Doctrine's type mapping matrix, json_array gets mapped to MySQL's MEDIUMTEXT column type, which by default obviously does not index its contents as json hence provides little to no performance advantage. (also, AFAICT, doctrine doesn't provide any json functionality besides converting db json from and to php arrays/nulls)
Maybe you could magically do some string search magic to extract a value to sort by it, but you still wouldn't get the performance boost a proper index provides. Depending on your data this could get noticably slow (and eat memory).
The JSON data type is fairly "new" to the relational database world and mappers like doctrine have not yet fully adopted it either. Extending doctrine to handle this data type will probably take lots of work. Instead you could rethink your table schema to include all the fields as columns you want to order by to use all benefits a relational database provides (like indexing).

Best way of saving object and it's type in MySQL database

Using an object oriented programming language I'm in situation where I have an Object where one of the properties is the type of the object. When I save it to the database I always create two tables, one for the object itself and the other one for the object type (id, name). Then I assign the typeId to the object and create a Foreign Key to ObjectType table. I'm not sure that this is correct because:
I'm using a whole table to save only few records (5-10 possible Object types) and they will be rarely updated.
I need to do a JOIN between two tables to show the name of the object type.
In the code I'm declaring constants with the same ID as in the type table (to operate when programming and assigning the type to object) and I don't like this redundancy.
The other option is to use a string and save it directly in the object´s table but this doesn't sound good because the search will be slower than with typeId and there is no list about all the possible types. Also changing the name of one type is more complicated. Can you advice me what is the best thing to do in this situation?
In this case, you have 3 options:
Varchar
Enum Fields
an other Joined table (Lookup table).
And you have 5 evaluation parameters:
Redundancy
Extendability
Modifiability
Performance
Simplicity
Varchar:
Very Bad (you should copy the values)
Good (you can add new types easily)
Very Bad (you should change all inserted data with the same value)
Excellent (based on reference)
Excellent (easy to use as other fields and in ORMs)
Enum Fields:
Good (DBMS control the redundancy)
Very Very Bad (based on reference)
Very Very Bad (based on reference)
Excellent (based on reference)
Very Good (some ORMs behave as String Field-see this reference)
an other Joined table (Lookup Table):
Excellent (ER normal method)
Excellent (ER normal method)
Excellent (ER normal method)
Normal (maybe bad - if the speed is so important)
Normal (depend on programmer)
References:
see Performance analysis here (Enum Fields VS Varchar VS Int + Joined table: What is Faster?).
see Enum advantages and disadvantages here (8 Reasons Why MySQL's ENUM Data Type Is Evil).
see Lookup table and Varchar example in mysql here in SO.
Finally: based on your evaluation parameters, you can choose the proper option.
The other possibility is to use just an Integer number in Database and manage all things in source code. I do not put it in evaluation because it is not database design. It is programming approach.

Doctrine2 Integer type with specified length

I'm making a symfony2 project using Doctrine 2 and i'm using Annotations to map my entities to a MySQL database.
I have read doctrine 2 documentation and it says that the length attribute applies only to the string type.
So my question is, is there a way to set a specific length (so no smallint, bigint and so on...) of an integer column through annotations (other than columnDefinition) and if not...why there isn't any? In Doctrine 1 i could specify a certain specific length for integer types
Because Doctrine is created for manipulating data using itself. And it is not care how this data will be displayed by another programs. But length definition for numeric values exist only for convenient displaying data in DB-managers (mostly for cli mysql client).
In Doctrine you also cannot create triggers for the same reason. You can implement such trigger with doctrine.

Insert id number instead of using Enum type - How much queries become slower?

sorry for my english (I'm posting from Italy) and (if it's possible) answer me with simple language (thanks)
I want you to know that I'm not a professional programmer: I'm just a fan of programming.
Here's the problem:
I'm going to create a table with four fields that contain repetitions of 6, 20, 165 and about 500 possible values (all varchar within 10 an 50).
My first idea was to use four table with only a field (primary Key) and four one-to-many relationships.
Later I read about Enum type of data and looked for a way for using this solution (because I thought that using all these varchar will absorb many bytes).
I've read a lot of web pages on the advantages and disadvantages of the Enum type, but I still have many doubts.
My problems with Enum type are:
1) I need never empty string (so I have to avoid any insert error by working in strict mode);
2) I'm afraid of possibles changing of the association between an Enum and the other data (for example if an Enum value disappear and I need to split Its data to the others)
So, I was scared by using Enum and I thought about using a third solution:
Given that the Enum type uses the numeric id of an array instead of a varchar, I thought about inserting an Id column (numeric) in the four tables and use the four Ids in the table with data instead of the string values.
And now the question:
Using this third way I'll need a very more complex query compared to using Enum for extraction of string data.
So I don't know which is best choice for save bytes without loosing time in extracting data.
Would you suggest me a choice?
How can I calculate the row limit beyond which a query will become sluggish?
Thanks in advance to anyone who will help me.
ENUM type is suitable for storing small number of values that are not supposed to change.
Your scenario is pretty common and the standard practice is to create four reference tables each with an ID field and a string value field, and then store those IDs in your main table.
Defining foreign key constraints ensures data integrity, and with indices your queries will be fast, do not worry about that at all.
Queries will not be complex, just needing four joins. It is also possible to create a view to avoid repeating the joins in different queries.
This solution is more flexible and easier to manage or port.

how to define integer array as a field when creating new table in mySQL

how to define integer array as a field when creating new table in mySQL
There is currently no way to store an array of integers in MySQL, so you should implement this by yourself. You could choose one of a few things, these two approaches included:
serialise the data with a separator (e.g. LONGTEXT: 123|4|65|864)
pack the integers into a blob (e.g. LONGBLOB: 0x0000007b000000040000004100000360)
You can't. You could do something like convert your array to a comma-separated string, and store this. Or you could define a normalised table structure and have each integer in it's own row. Each row for a given array would also contain some kind of array key as a separate field. This also has the advantage that you can easily query for individual array elements.
Edit In my view the first option is not very elegant. Unless you define your field as TEXT you're going to have issues with varying string lengths, and defining your field as VARCHAR(10000) or whatever is not very efficient. Certainly if your array lengths are long you should consider a normalised solution.