Saving user interactions and presenting them - mysql

I have a site where users vote on polls. They can also like these polls. When they scroll through their feed, the questions they've liked will be represented by a like icon being filled (kind of like Facebook or Instagram). Their votes will also be shown if they already voted for the polls on the generated feed.
As the website is scaling, getting their likes and votes to be queried for each question is taking a long time since there are now millions of votes. My question is how do I make this process faster? Currently, I use MySQL to store the data.
My thought is to use a cache store like Redis and store all their likes and votes for each question in this type of structure:
User_id:
likes: [question_ids]
votes: [question_ids]
where user_id is a dictionary key that contains values of array types. The feed gets loaded from the cache, for each question, we check if that question is liked or voted by the user. I'm not sure if this approach is the "best" or if there's another way of doing things. I'm wondering how Facebook, Instagram, Twitter, etc. save user interactions and how they query them.
Tables:
Question Table (simplified)
id question total_votes total_likes
Choice Table (One question has two choices)
id question_id choice votes
Voting table
id user_id choice_id
Like Table
id user_id question_id
Query to get the newest questions:
SELECT `core_question`.`id`, `core_question`.`user_id`,
`core_question`.`status`,
`core_question`.`total_votes`, `core_question`.`like_count`,
`core_question`.`comment_count`, `core_question`.`created_at`,
`core_question`.`slug`, `core_question`.`flag`,
`core_question`.`spam_flag`,
( SELECT U0.`is_liked`
FROM `core_like` U0
WHERE (U0.`question_id` = `core_question`.`id`
AND U0.`user_id` = 1)
LIMIT 1
) AS `like_selected`,
( SELECT U0.`choice_id`
FROM `core_voting` U0
INNER JOIN `core_choice` U1 ON (U0.`choice_id` = U1.`id`)
WHERE (U1.`question_id` = `core_question`.`id`
AND U0.`user_id` = 1)
LIMIT 1) AS `choice_selected`,
COUNT(CASE WHEN `oauth_following`.`follower_id` = 1
THEN `oauth_following`.`id`
ELSE NULL END ) AS `is_following`
FROM `core_question`
INNER JOIN `oauth_user` ON (`core_question`.`user_id` = `oauth_user`.`id`)
LEFT OUTER JOIN `oauth_following` ON (`oauth_user`.`id` =
`oauth_following`.`target_id`)
WHERE NOT (`core_question`.`user_id` IN (4, 5, 6, 7))
GROUP BY `core_question`.`id`
ORDER BY `core_question`.`id` DESC

I suggest these indexes:
core_question: INDEX(user_id)
oauth_following: INDEX(target_id, follower_id)
core_like: INDEX(question_id, user_id, is_liked)
core_choice: INDEX(question_id)
core_voting: INDEX(user_id, choice_id)

Related

SQL INSERT INTO two tables from one table

Consider the app Tinder and the following numbers:
(User_id, target_id)
(1,2);
(2,1);
(3,5)
(5,3);
(4,1);
This means that 1 and 2 have matched, and 3 and 5, but not 4 and 1.
Now for my question. I have two tables in MySQL database currently. User and Likes.
Where User has bunch of values, but id is the important one (image 1).
Likes has two values: user_id and target_id (image 2).
How should I approach getting the data from User into the columns of Likes? This should result in the target_id and user_id of Likes having the same values as idof User. Am I even going at this correctly?
I know that one has a bunch of columns, and the other has two, and that is where I can't figure out any more.
Your question is kind of vague. Actually I don't know if you want to filter out the non-paired users or you just wanna to include the users info to the "Like". I think you want to find which user pairs like each other.
to do so you can use a query like this:
CREATE TEMPORARY TABLE LikeEachOther(
SELECT DISTINCT‌ L1.user_id, L1.target_id
FROM Likes L1, Likes L2
WHERE‌ L1.user_id = L2.target_id and L2.user_id = L2.target_id
);‌‌‌
SELECT *
FROM LikeEachOther LEO, User U1, User U2
WHERE U1.User_id = LEO.USer_id and U2.User_id = LEO.target_id

Randomize a winner pair from the subscriptions

I have a project, where customer needs a winnner pair for events. The users of this site can "like" other user's (just like on FB), they subscribe to a particular post, and the script will generate a winner pair from the subscribers.
So I need a SQL query to randomize a winner pair from the list of pairs, where the users liked each other, and subscribed to a particular post.
How do i do that ?
I cant write a query that, because i got unexpected results.
I have 3 tables : events, likes, subs (and users ofc)
events table : event_id, event_name
subs table: sub_id, event_id, uid
likes table: liker, liked (the two uid from the users table)
Now I can make pairs from the likes table (i self-joined the table where liker = liked AND liked = liker) and randomized, but how can I join the subs and the events tables to the likes table to achieve that a randomized pair will be a subscribed users for a particular event too ?
My current query looks like this :
SELECT L.liked AS T1, L.liker AS T2
FROM likes AS L, likes AS K
WHERE L.liked = K.liker
AND L.liker = K.liked
ORDER BY rand( )
LIMIT 0 , 1
I googled everything about joins for one week, but i cant achieve that.

A request to get a Twitter feed like?

How does Twitter (or Facebook) do to retrieve a user feed?
Here is the database schema I am working on. I renamed everything to look like twitter hoping that the most of you would understand my question...
I only have two resources: users and tweets. So here are those two tables:
users:
- id
- username
tweets:
- id
- author_id
- content
Let's continue with a simple pivot table to associate tweets and users:
user_tweet:
- user_id
- tweet_id
- created_at
This pivot table is here mainly to store the retweets. But it also stores the original tweets for more convenience.
For example, let's take user 1 tweets 'something'. user 2 and user 3 retweet. The user_tweet table will have three rows.
And, let's see a last table that complicates everything: The Following System.
Every user can follow an other user. I named the table "followee_follower":
followee_follower:
- followee_id
- follower_id
The followee_id is the user.id of the person being followed
The follower_id is the user.id of the person that follows an other one
Now let's get to the SQL problem:
I'm user 1. I follow user 2, and user 3.
How can I retrieve the tweets and retweets from user 2 and user3 knowing that I want to retrieve them ordering them by the created_at field of the user_tweet table, and that I don't want to get two similar tweets.
Many thanks, any help is highly nice from you,
Have a good day/night.
EDIT: Here are some samples data from tables:
users table
tweets table
user_tweet table
followee_follower table
expected results
I'm not sure I completely understand your question (sample data would help), but I think you just need to use multiple joins:
select t.id, t.content, ut.created_at
from tweets t
inner join user_tweets ut on t.id = ut.tweet_id
inner join followee_follower ff on ut.user_id = ff.follower_id
where ff.followee_id = 1
order by ut.created_at
Perhaps if a user retweets, you'd want to do something like this instead to get the first tweet (assuming the id and created_at fields both should return the minimum):
select t.content, min(t.id), min(ut.created_at)
from tweets t
inner join user_tweets ut on t.id = ut.tweet_id
inner join followee_follower ff on ut.user_id = ff.follower_id
where ff.followee_id = 1
group by t.content
order by min(ut.created_at)

Mysql COUNT VS num rows performance

I want to select the amount of forum posts compared to a list of users. So it will look like this:
USERID --- FORUMPOSTS
3647 - 2
7467 - 14
2673 - 39
3224 - 5
... and so on
Now I'm asking if it would be faster to count the forum post via COUNT(*) or looping through the userlist before and creating a new query for each user to count his/her forum posts via mysql_num_rows.
You can let SQL do the grouping and counting
select userid, count(*) as forumposts
from your_table
group by userid
Now I'm asking if it would be faster to count the forum post via COUNT(*) or looping through the userlist before and creating a new query for each user to count his/her forum posts via mysql_num_rows.
It'll be faster to do the former, "count the forum post via COUNT(*)". You can group the results as follows:
SELECT userid, COUNT(*) FROM my_table GROUP BY userid
It'll be even faster still if your table has an index on the userid column.

Mysql - Select user only once when subscribed to multiple categories

Good day,
Currently I am working on a project, and I am kinda stuck. It is a relative simple table where this question is about (see this photo: http://cl.ly/5M0x ).
There is a user_id collumn and a categorie_id collumn, each representing an id from another table (users and categories). Now I am trying to get the number of users within each category which is simple and can be done like:
'SELECT COUNT(uc.user_id) as total FROM xs2media_users_categories as uc GROUP by uc.categorie_id'
However what I want is that when a user has been counted for a certain category it won't be counted for another categorie where it is subscribed to. So for example if user number four is subscribed to category 2, it will increment the count of that, but not for category 3 anymore, even though he could be subscribed to that category too.
Hope this makes sence.
Thanks.
The following query picks one category for each user, and then counts the nr of users per each category.
select categorie_id
,count(*)
from (select user_id
,min(categorie_id) as categorie_id
from xs2_media_users_categories
group
by user_id
) u
group
by categorie_id;
Is this what you are looking for?