Handle already-liked pictures in SQL-Database efficiently - mysql

I'd like to check; if a user has already liked a picture via MySQL.
I know that it would be easy to make a table with the entities like:
id
userFK
picturesFK
which goes one additional record each time, a user likes a picture.
But the table would be huge
for example 1000 users like 1000 posts, the table already has 1 million entries.
Is there a more efficient way to achieve this check?

Fundamentally, the fact that the user has liked the picture has to be stored somewhere, so no, I don't think there is a way around the fact that if 1000 users like 1000 pictures each, you will have 1 million records somewhere.
However, you could optimize this by not having an id column (which would presumably be the primary key). Normally I would not recommend creating a table without a primary key, so you would instead want to make the entire table the primary key, i.e., with PRIMARY KEY (userFK, picturesFK). This has some disadvantages but it makes the table 1/3 smaller.

Related

Is it good to have a table with more rows or more tables with less rows in a database?

I am building a database for my application using Mysql, contains 2 tables in which one table will have user details and other table will have all user's activities(say posts,comments,..). I have 2 approaches for this PS.
Group all users activities under one table(say useractivities).
Maintain specific activities table for each user(say user1activity,user2activity,...).
If we go with approach 1, it builds time complexity in case of more users.
with approach 2, eats up database. which design will show less time and space complexity?
For better database maintain, you have to go with the first approach because you can normalize data easily.. and the perfect way to manage database structure, Need to take care of below points
You have to give proper indexing in user_id field for fast result in join query.
In case of large number of records in one table, then you can create another table like user_activities_archive for store old activities. in the regular period, you can move an old record from user_activities to user_activities_archive
You can create multiple tables for user_posts, user_comments instead of user_Activities for more splitting data and different structures of the table, for example you can manage replyto_id in the comment table and user_post table might have title field.
In the second approach for cerate tables for each user, there are many limitations like
Very hard in case of Table Joining with other tables
In case of fetch all user's activity records, you cant do it.
A number of the user base of your application.
Limitation of a number of tables in the database.
Create more complexity in edit update or delete user records.
If the user is not active (just registered) then separate user table useless.
As juergen d mentioned in the comment, approach 2 should not be used.
However I would consider splitting useractivities into different tables if the possible user activites are different from each other to avoid unneccessary column.
Example: A comment table with information about who made the comment (foreign key to user table) and the comment itself. + A foreign key to another user activity to wich the comment was made.
The comment column in the above table does not make sence for say, just a like of a post, so I would have created a different table for likes.

A seperate table for the posts which each user has liked - practical or not?

In a social networking site I'm making, I need some way to store which posts a user has 'liked', to ensure they can only 'like' each post one time. I have several ideas.
A seperate table for each user, to store all of the different posts' IDs which they've liked as rows in said table.
A space-seperated string of post IDs as a field in the table users.
A seperate table for each post, storing all of the different users' IDs which have liked said post as rows in the table.
note, users is a table containing all of the site's users, with their ID, username, etc.
-
Initially I liked the idea of a seperate table for each user, but I realised this might be more trouble than it's worth.
So I thought a space-seperated string for each row in users might be a good idea, since I wouldn't have to start working with many more tables (which could complicate things,) but I have a feeling using space-seperated strings would lower performance significantly more than using additional tables, especially with a greater amount of users.
Essentially my question is this: Which, out of the aforementioned methods of making sure a user can only like a post once, is the most practical?
None of these sound like particularly good ideas.
Generally, having to create tables on the fly, be it for users or posts, is a bad idea. It will complicate not only your SQL generation, but also clutter up the data dictionary with loads of objects and make maintaining the database much more complicated than it should be.
A comma-delimited string also isn't a good idea. It breaks 1NF will complicate your queries (or worse - make you right code!) to maintain it.
The sane approach is to use a single table to correlate between users and posts. Each row will hold a user ID and the ID of a post he liked, and creating a composite primary key over the two will ensure that a user can't like a post twice:
CREATE TABLE user_post_likes (
user_id INT, -- Or whatever you're using in the users tables
post_id INT, -- Or whatever you're using in the posts tables
PRIMARY KEY (user_id, post_id),
FOREIGN KEY (user_id) REFERENCES user(id),
FOREIGN KEY (post_id) REFERENCES post(id)
);

Relational database in phpmyadmin

I have two tables set up in phpmyadmin- table userid and table data. The userid table has a single column userid which is the primary key. The table data has id|name|src| and a bunch of other information. The issue right now is that the column id which is a 16 character long string acts as a primary key in table userid and foreign key in table data. Now if the same user wants to upload more than one image then i am having to repeat the id in the table data and the table is becoming very large. Is there any other way to go about this(i am relatively new so im sorry if this sound rather stupid.). Finally is there actually any performance boost in this situation by indexing the id of the user in the other table as to me it seems like just a waste of space as im haveing to repeat the user id one more time in the table userid as compared to having a single table to hold both data and user id.
This is the case with One to Many Relations. I don't think that the table will grow that large to give you issues. This would be the way to go.
Alternatively, a strategy used by many cms and platforms to store settings. You can store JSON object having src of image into the image column. But this will add the overhead of updating image information every time a image created and deleted.
Short answer: No. You will have to repeat the userid otherwise you won't know who it belongs to.

Store Follows of users in a table

I've got the following situation: I want to store data, which represents, if a user is following another user. Another table, which I cannot touch, stores the users, where the username is the primary key (unfortunatly no id...).
The fact is, if one user follows another one, it doesn't mean, that the other one is following the first one.
Right now, I designed the table with two varchar's (128) and a UNIQUE INDEX on these two varchar's which represent the usernames.
The problem is, that I need to parse some old-styled system now, and I finished like 15% and I've got 550k entries on this table already.
The index is bigger then 16MB, and the data just 14MB.
What could I do, to save this data in a better way? As said, I cannot use id's instead of the usernames, because the user-table uses the username as primary key.
As you have noticed, creating a seperate index on all columns essentially forces MySQL to duplicate all data in the index.
Instead of creating a seperate unique index, you can create a primary key consisting of both of your fields. MySQL uses the primary key as a clustered index making sure your uniqueness constraint is still satisfied without increasing the size of your database.
You might consider building your own index table that contains ID > username.
You could then use the ID's to map the followers.
This will cause for some extra overhead if you want to retrieve all the data.

Different database tables joining on single table

So imagine you have multiple tables in your database each with it's own structure and each with a PRIMARY KEY of it's own.
Now you want to have a Favorites table so that users can add items as favorites. Since there are multiple tables the first thing that comes in mind is to create one Favorites table per table:
Say you have a table called Posts with PRIMARY KEY (post_id) and you create a Post_Favorites with PRIMARY KEY (user_id, post_id)
This would probably be the simplest solution, but could it be possible to have one Favorites table joining across multiple tables?
I've though of the following as a possible solution:
Create a new table called Master with primary key (master_id). Add triggers on all tables in your database on insert, to generate a new master_id and write it along the row in your table. Also let's consider that we also write in the Master table, where the master_id has been used (on which table)
Now you can have one Favorites table with PRIMARY KEY (user_id, master_id)
You can select the Favorites table and join with each individual table on the master_id and get the the favorites per table. But would it be possible to get all the favorites with one query (maybe not a query, but a stored procedure?)
Do you think that this is a stupid approach? Since you will perform one query per table what are you gaining by having a single table?
What are your thoughts on the matter?
One way wold be to sub-type all possible tables to a generic super-type (Entity) and than link user preferences to that super-type. For example:
I think you're on the right track, but a table-based inheritance approach would be great here:
Create a table master_ids, with just one column: an int-identity primary key field called master_id.
On your other tables, (users as an example), change the user_id column from being an int-identity primary key to being just an int primary key. Next, make user_id a foreign key to master_ids.master_id.
This largely preserves data integrity. The only place you can trip up is if you have a master_id = 1, and with a user_id = 1 and a post_id = 1. For a given master_id, you should have only one entry across all tables. In this scenario you have no way of knowing whether master_id 1 refers to the user or to the post. A way to make sure this doesn't happen is to add a second column to the master_ids table, a type_id column. Type_id 1 can refer to users, type_id 2 can refer to posts, etc.. Then you are pretty much good.
Code "gymnastics" may be a bit necessary for inserts. If you're using a good ORM, it shouldn't be a problem. If not, stored procs for inserts are the way to go. But you're having your cake and eating it too.
I'm not sure I really understand the alternative you propose.
But in general, when given the choice of 1) "more tables" or 2) "a mega-table supported by a bunch of fancy code work" ..your interests are best served by more tables without the code gymnastics.
A Red Flag was "Add triggers on all tables in your database" each trigger fire is a performance hit of it's own.
The database designers have built in all kinds of technology to optimize tables/indexes, much of it behind the scenes without you knowing it. Just sit back and enjoy the ride.
Try these for inspiration Database Answers ..no affiliation to me.
An alternative to your approach might be to have the favorites table as user_id, object_id, object_type. When inserting in the favorites table just insert the type of the favorite. However i dont see a simple query being able to work with your approach or mine. One way to go about it might be to use UNION and get one combined resultset and then identify what type of record it is based on the type. Another thing you can do is, turn the UNION query into a MySQL VIEW and simply query that VIEW.
The benefit of using a single table for favorites is a simplicity, which some might consider as against the database normalization rules. But on the upside, you dont have to create so many favorites table and you can add anything to favorites easily by just coming up with a new object_type identifier.
It sounds like you have an is-a type relationship that needs to be modeled. All of the items that can be favourited are a type of "item". It sounds like you are on the right track, but I wouldn't use triggers. What could be the right answer if I have understood correctly, is to pull all the common fields into a single table called items (master is a poor name, master of what?), this should include all the common data that would be needed when you need a users favourite items, I'd expect this to include fields like item_id (primary key), item_type and human_readable_name and maybe some metadata about when the item was created, modified etc. Each of your specific item types would have its own table containing data specific to that item type with an item_id field that has a foreign key relationship to the item table. Then you'd wrap each item type in its own insertion, update and selection SPs (i.e. InsertItemCheese, UpdateItemMonkey, SelectItemCarKeys). The favourites table would then work as you describe, but you only need to select from the item table. If your app needs the specific data for each item type, it would have to be queried for each item (caching is your friend here).
If MySQL supports SPs with multiple result sets you could write one that outputs all the items as a result set, then a result set for each item type if you need all the specific item data in one go. For most cases I would not expect you to need all the data all the time.
Keep in mind that not EVERY use of a PK column needs a constraint. For example a logging table. Even though a logging table has a copy of the PK column from the table being logged, you can't build a constraint.
What would be the worst possible case. You insert a record for Oprah's TV show into the favorites table and then next year you delete the Oprah Show from the list of TV shows but don't delete that ID from the Favorites table? Will that break anything? Probably not. When you join favorites to TV shows that record will fall out of the result set.
There are a couple of ways to share values for PK's. Oracle has the advantage of sequences. If you don't have those you can add a "Step" to your Autonumber fields. There's always a risk though.
Say you think you'll never have more than 10 tables of "things which could be favored" Then start your PK's at 0 for the first table increment by 10, 1 for the second table increment by 10, 2 for the third... and so on. That will guarantee that all the values will be unique across those 10 tables. The risk is that a future requirement will add table 11. You can always 'pad' your guestimate