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.
Related
Let's assume a user is following thousands of other people,
These people send news regularly, and in his/her page, our user wants to see the recent news (paginated) from these people only.
What is the most efficient way to do this?
This is what I'm doing currently:
Create a table called following in database, each follow is added here, id, user_id, following_user_id
Get a list of user's following_user_ids
fetch all news WHERE user_id (news poster id) is IN(...following_user_ids...)
For example if our user's id is 1:
SELECT `following_user_id` FROM `following` WHERE `user_id` = 1; /* This is used in the IN() below */
SELECT * FROM `news` WHERE `user_id` IN (4,11,7,...following_user_ids....) ORDER BY `id` DESC limit 50 offset 0
/* Of course the `user_id` is indexed in the `news` table */
But if the user is following thousands of people and the news table is huge, I'm assuming the IN (... thousands of IDs ...) will be very slow?
So, is there a more efficient way to do this?
EDIT:
In case any one also has this issue, just stick with the IN method, it is a lot faster than JOIN in my case.
select
news.*
from
news
join following on news.user_id=following.following_user_id
where
following.user_id=1
Pagination
OFFSET has a problem. As he pages forward/backward and others are inserting new rows, he will miss stories or see the same story twice on consecutive pages.
The solution is to "remember where you left off". More: http://mysql.rjweb.org/doc.php/pagination
JOIN
The JOIN approach is cleaner, but not necessarily faster. In either case, the end result is a large list of stories, of which he is only interested in a page's worth. Shoveling the rest around is costly.
The fix for this is to find only the ids of the stories while finding the page's worth. Then look up (via another JOIN) the rest of the data for each story.
Prebuilt list
Still, if there are thousands of followed people (or millions of followers, in the case of Trump), it gets quite costly. There is a technique for making the SELECT faster at the cost of INSERTs needing to run around and store information.
Have a new 3-column table: (1) follower_id, (2) timestamp, (3) story_id. Whenever a story is posted, one row per follower is added to this table. When a follower wants the latest stories, it is sitting right in this table (or at least the ids are).
More: http://mysql.rjweb.org/doc.php/lists
You can limit your search by using the 'LIMIT' function, that will need to be updated everytime the user want more information:
LIMIT [offset,] row_count;
Putting it in your example would be something like this, saving this select in a temporary table variable:
SELECT * FROM `following_user_ids` ORDER BY `id` DESC limit rowcount offset offset_variable;
If you want to put in the example of a social media, you can update the limit everytime the user asks for more posts, so that the user will be able to see the posts of several of the he follows.
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.
I have a site which display images, up to 30 per page.
Users can comment on the images and these comments, or at least the first few, appear under the image if there are comments.
I have a table of image references linked to a folder on my server.
e.g.
image_id // image id
user_id // user who added
image_url // ref to image
Then a separate table for all comments
comment_id
image_id // link to images table
comm_poster_id // id of user who posted comment
Now, the question is what the best way to call the information together? Ideally in one select
I can't really ajax call under each image as that would be 30 db calls per page which would kill it so whats the alternative/best method?
To clarify, in the select there would only ever be 1 image but there could of course be multiple comments for an image
Hope i've given enough info
EDIT To clarify, the question is what is the best way to collate all this information together for display - can I run one query which pulls all the images in on the page also somehow pulls the comments for images in if they exist.
As for how I would like the data to look... I don't know. This is the first time I've done anything like this so guidance needed if possible.
Ok, well I'm not a php expert, but I got you started on the sql side of things. I CAN help you with php, but there are others here that are more versed in it that I am.
I started this sqlFiddle for you, go have a look and you can tinker with the query to get what you want.
http://sqlfiddle.com/#!2/79ecf/1/0
From the php side, until you know how you want to display your data, it's difficult to say what your query needs to look like. I went with this for the time being:
select *
from images i
inner join comments c on i.image_id=c.image_id;
This is a VERY simple query and you will probably end up needing to add to it.
I'll assume you are using mysql as most people using php choose mysql. From my understanding there are 2 ways to connect, mysqli and pdo. PDO seems to be emerging as the preferred method, but I know nothing about it. Here are references for both. Just DO NOT USE mysql_query(), it is deprecated so don't bother learning any part of it.
PDO: http://dev.mysql.com/doc/refman/5.6/en/apis-php-pdo-mysql.html
MYSQLI: http://php.net/manual/en/mysqli.query.php
Either of these should give enough of a tutorial to show you how to query your database and then loop through the results to get to your data. It is then up to you how you want to display it on your page.
Hopefully this is enough to point you in the right direction.
Good Luck!
Your easiest approach is to just join the two tables together, sorting first by image and sub-sorting by comment.
SELECT i.*, c.comment_id, c.comm_poster_id
FROM images i LEFT JOIN comments c ON i.image_id=c.image_id
WHERE {whatever where clause selects your set of 30 images}
ORDER BY i.image_id, c.comm_poster_id
Use a LEFT JOIN or images without comments won't display.
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.