I want to do this below to notify user but I am not sure about quality and slow query:
When someone insert new message to group chat SQL will select all members of group chat and then in the loop for each user it will insert user_id group_id unseen_message_count.Is that too heavy to do for each message in the chat because sometime people write really fast and doing this for each message?Have better option?
Update version
My sql is like below:
chat_seen table
user_id | group_id | unseen_count
when new chat inserted I will update unseen_count for each user then when they see unseen_count,I will update unseen_count to 0.I think it is heavy if I do this for each member of group,Is not it?
Your question is a bit vague, and it doesn't sound like a great solution, but not terrible either. The important thing to remember, is to ensure there are indexes on all the fields in your WHERE statements (e.g. group_id, user_id, etc).
You should also think about whether simply storing the id of the last message read for each user, might be enough to calculate that count without having to constantly update so many rows every time a message is posted.
Related
I want to improve the speed of a notification board. It retrieves data from the event table.
At this moment the events MySQL table looks like this
id | event_type | who_added_id | date
In the event table I store one row with information regarding a particular event. Each time a users A asks for new notifications, the query runs through the table and looks if the notifications added by the user B suit him (they have to be friends, members of the same groups, have previously chatted).
Table events became big, because of the bulky query the page loads slow.
I'm thinking of changing entirely this design and, instead of adding one event row and then compare if the user's event suits or not, to add as many rows as interested users. I would change the table events structure as follows:
id | event_type | who_added_id | forwho_id | date
Now, if user B creates an event which interests other 50 members, I create 50 rows with the same information and in the 'forwho_id' field I mention those 50 members which must get this notification.
I think the query will become much more simple and it will take less time to search through it.
How do you think:
1. Is this a good approach in storing such kind of data or we should avoid duplicate data at any cost?
2. How do you think the events table will behave if the number of interested users will be not 50 but hundreds?
Thank you for reading this and I hope I made myself understandable.
Duplicated data is not "bad", and it's not to be "avoided at all cost".
What is "bad" is uncontrolled redundancy, and the kind of problems that come up when the logical data model isn't third normal form. It is acceptable and expected that an implementation will deviate from a logical data model, and introduce redundancy for performance.
Your revised design looks appropriate for your needs.
I'm rebuilding an add-buddy module and I have a question about the database table design.
In the current version i have a design like this:
id | user1_id | user2_id | status
Each time an user invites another, two rows are created, in one row the current users id is placed in the field user1_id, in the next row the users id is placed in user2_id, which enables me to use a rather simple MySQL query in the list mode of the module:
WHERE a.id=b.user2_id AND b.status = 1 AND b.user1_id = '".$get_user."'
Now, i try to find another way to build this, as i would prefer to have only one row for each friendship, instead of the currently used two.
I have come up with several approaches for table-design and building the logged in users buddylist and i would like to see your opinion about this.
using only one field "ids" for both users ids, comma-seperated. in the select-query i check if the field ids contains the logged in users id, probably using LIKE for that. Than in the while loop i would remove the current users id from the field with str_replace($current_user_id, '', $row['id']);
one row, with fields id1 and id2, using a simple OR in the select-query, in the while loop for building the list i would place an if-statement:
if ($row['id1'] == $current_user_id) use $row['id2'] else use $row['id1']
using two select-queries with UNION like this:
(select * from users where id1 = user_id)
UNION
(select * from users where id2 = user_id)
What do you think of this approaches would be the best for this kind of thing, or do you have another idea?
Edit: thought i would have found an easy solution for table and a matching query, but didnt work, so i deleted it.
Like #Nonym suggested, you could use the status column. Set -1 when the friendship is awaiting confirmation, 0 when the friendship has been denied, and 1 if the friendship is accepted.
Getting a list of all friends for a certain user ID is as simple as calling:
SELECT user2_id FROM users WHERE status = 1 AND user1_id = <your user id> .
Since your database is going to be filled with denied invitations, you could have a cronjob running every 24 hours or so, which will delete all denied invitations, reducing space. A query like
DELETE FROM users WHERE status = 0
would be of use. Actually, you can move even further and add another field called date, which will indicate the date when the request was sent and in the same cronjob include deleting records with status = -1, which have been in the table for too long.
EDIT
Just like #jayden said, the user_id's may be mixed, so the best way is to keep these two consistent. Like user1_id being always the current user and user2_id being the receiver. And to know, who invited who, add another field like addressee or any other (probably) more suitable name, which will hold the id of the user who initiated the request.
For starters, and while waiting for a response to the comment, I'll have to say this as soon as possible:
Approach # 1: Try to avoid doing this as much as possible. Data should be what it is; data, so refrain (when you can) from putting logic into the data. Put your logic perhaps in a view, function or stored procedure :)
[edit]
Now I'm confused. Let's take a step back, shall we?
First, you have a table that appears this way (and I will just make a rough 'sketch' of it) :
TABLE USERS
id (auto increment?)
user1_id (the one initiating the friendship invite)
user2_id (the one user1_id is inviting to form a friendship)
status (the status of the friendship; like
A record is added to the table USERS when:
A user, whose id goes into user1_id invites someone whose id then goes into user2_id , and a status is set to mean something like 2 if an invite had just been sent, and 1 if it was accepted or perhaps 0 if it was rejected, etc
What part/s in the above statements is/are incorrect?
[edit] part ii:
Everything aside, if it comes down to:
Get all records where the viewing user is either an initiator (user1_id) or is a recipient of a buddy request (user2_id)
Then you don't really need a union:
SELECT
CASE
WHEN user1_id = <Id_Of_Viewing_User> THEN user2_id
WHEN user2_id = <Id_Of_Viewing_User> THEN user1_id
END AS user_id
FROM users
WHERE
user1_id = <Id_Of_Viewing_User>
OR
user2_id = <Id_Of_Viewing_User>
Can you try the SQL above? That way, you won't need to worry about the programming part. Whatever comes out in user_id is the id of someone who has either requested to be the viewing user's friend of someone the viewing user requested to be a buddy with.
Is this... anywhere.. anywhere at all.. near what you want?
I have a list of events for example I wanna show on a page with the users that have created them which is all in a table and the user who has created them's unique id, now if I wanna show their username and avatar I would have to run 100 queries inorder to show 100 events! but I'm sure their is a easier way I don;t know!
i have a table (user_table) with fields user_id INT(8) and user_photo VARCHAR(255)
and I have another table (user_event_table) with event_id INT(8), event_user_id INT(8), event_details TEXT
so I want to show a list of all these events but I want to next to it show the user_photo !
Learn to join with SQL. It's fundamental to relational databases.
SELECT * FROM user_event_table uet
LEFT JOIN user_table ut
ON ut.user_id = uet.user_id
Now each record will have a username and photo string.
Show us your tables, along with the query you're currently using, in a different question and people will help you with the SQL.
Yes. Get the accurate current time at the start of your PHP script, and get the time at the end, and log the page name and the difference in times.
If you're worried about this, you need to conduct a security audit of your scripts. There's no easy way to tell what someone who has access to your page's contents will leak.
Again, you need a real security audit. Someone will have to read and understand all the code in order to be sure. There's no easy way.
On a social network I am working on in PHP/MySQL, I have a friends page, it will show all friends a user has, like most networks do. I have a friend table in MySQL, it only has a few fields. auto_ID, from_user_ID, to_friend_ID, date
I would like to make the friends page have a few different options for sorting the results,
By auto_ID which is basically in the order a friend was added. It is just an auto increment id
new friends by date, will use the date field
By friends name, will have a list in alphabetical order.
The alphabetical is where I need some advice. I will have a list of the alphabet A-Z, when a user clicks on K it will show all the user's name starting with K and so on. The trick is it needs to be fast so doing a JOIN on the user's table is not an option, even though most will argue it is fast, it is not the performance I want for this action. One idea I had is to add an extra field to my friendship table and store the first letter of the users name in it. User's can change there name at anytime so I would have to make sure this is updated on possible thousands of records, anytime a user changes there name.
Is there a better way to do this?
Well if you don't want to do a join, then storing the user's name or initials on the friendships table is really your only other viable option. You mention the problem of having to update thousands of records every time a name changes, but is this really a problem? Unless you're talking about a major social networking site like Facebook, or maybe MySpace, does the average user really have enough friends to make this problematic? And then you have to multiply that by the probability that a user will change their name, which I would imagine isn't something that happens very often for each user.
If those updates are in fact non-trivial, you could always background or delay that to happen during non-peak times. Sure you would sacrifice up-to-the-second accuracy, but really, would most users even notice? Probably not.
Edit: Note, my answer above really only applies if you already have those levels of users. If you are still basically developing your site, just worry about getting it working, and worry about scaling problems when they become real problems.
You could also look at a caching solution like memcached. You can have a background process that is always updating a memcached hash and then when you want this data it is already in memory.
I'd just join on the table that contains the name and then sort on the name. Assuming a pretty normal table layout:
Table Person:
ID,
FirstName,
LastName
Table Friend:
auto_ID,
from_user_ID,
to_friend_ID,
date
You could do things like:
Select person.id, person.firstname, person.lastname, friend.auto_id
from Friend
left join on person where person.id = friend.to_friend_ID
where friend.from_user_ID = 1
order by person.lastname, person.firstname
or
Select person.id, person.firstname, person.lastname, friend.auto_id
from Friend
left join on person where person.id = friend.to_friend_ID
where friend.from_user_ID = 1
order by friend.date desc
I'd really recommend adding a column in the friend table to keep the first letter around, no need to duplicate data like that (and have to worry about keeping it in sync), that's what joins are for.
I'm working on a PHP app that has several objects that can be commented on. Each comment can be voted on, with users being able to give it +1 or -1 (like Digg or Reddit). Right now I'm planning on having a 'votes' table that has carries user_id and their vote info, which seems to work fine.
The thing is, each object has hundreds of comments that are stored in a separate comments table. After I load the comments, I'm having to tally the votes and then individually check each vote against the user to make sure they can only vote once. This works but just seems really database intensive - a lot of queries for just the comments.
Is there a simpler method of doing this that is less DB intensive? Is my current database structure the best way to go?
To be clearer about current database structure:
Comments table:
user_id
object_id
total_votes
Votes table:
comment_id
user_id
vote
End Goal:
Allow user to vote only once on each comment with least # of MySQL queries (each object has multiple comments)
To make sure that each voter votes only once, design your Votes table with these fields—CommentID, UserID, VoteValue. Make CommentID and UserID the primary key, which will make sure that one user gets only one vote. Then, to query the votes for a comment, do something like this:
SELECT SUM(VoteValue)
FROM Votes
WHERE CommentID = ?
Does that help?
Why don't you save the totaled votes for every comment? Increment/decrement this when a new vote has happened.
Then you have to check if the user has voted specifically for this comment to allow only one vote per comment per user.
You can put a sql join condition which returns all the votes on comments made by the current user for this object, if you get no rows, the user hasn't voted. That is just slightly different from you checking each comment one by one in the program.
as far as the database structure is concerned, keeping these things separate seems perfectly logical. vote { user_id, object_id, object_type, vote_info...)
You may be already doing this, sorry but I couldn't interpret from you post if that was the case.