More efficient way to fetch data from MySQL - php

Suppose I have a MySQL table called "User".
ID, Name, Email, Age, Gender, Country, Hometown, City, Address, Relationship_Status, Employment_Status, IP, Registered_Time
Now, which query is more efficient to fetch all info of a user?
A)
SELECT * FROM User WHERE id=1
B)
SELECT ID FROM User WHERE id=1
SELECT Name FROM User WHERE id=1
SELECT Email FROM User WHERE id=1
SELECT Age FROM User WHERE id=1
SELECT Gender FROM User WHERE id=1
SELECT Country FROM User WHERE id=1
SELECT Hometown FROM User WHERE id=1
SELECT City FROM User WHERE id=1
SELECT Address FROM User WHERE id=1
SELECT Relationship_Status FROM User WHERE id=1
SELECT Employment_Status FROM User WHERE id=1
SELECT IP FROM User WHERE id=1
SELECT Registered_Time FROM User WHERE id=1
Thing is, depending on situation, I may or may not need all of the data. So, should I just fetch each data one by one when I need them or should I fetch all the data at once and then use as I need?
Thanks for helping!

A single query fetching multiple columns is almost always more efficient than multiple queries. Why? The query must be serialized by php, sent to the mySQL server, deserialized. Then the mySQL server has to do the WHERE operation to find the appropriate row or rows. Finally it has to serialize the results and send them back to php. The less you do all this, the less work the system has to do.
Pro tip: Don't use SELECT * . Instead enumerate the columns you want, like so.
SELECT ID, Name, Email, Employment_Status, Registered_Time
FROM Users
WHERE ID = 1
There are a lot of advantages to that approach, especially in queries that return many rows (which yours does not).

Each query to database costs something. PHP has to send the query to SQL server, the query analyzer has to parse your query, optimize it, translate it into some internal code, lookup the table, seek in the index file on the disk, seek in the data file on the disk.
The cost of selecting all columns at once using SELECT * is almost the same as cost of selecting a single column individually in one sql query.
When the data is read from the file on disk, it won't read just the 10 bytes you need, data from disk is always read in much bigger chunks by the operating system (like 4KB, it may depend).
Selecting one column like "SELECT Age ..." will read from disk the entire row anyway in vast majority of cases.
So to answer your question, SELECT * in your example will be more efficient since you'll go through the overhead of parsing a query just once.

Related

Selecting data for each user from multiple tables

I'm trying to add a function to a script that orders a list of users and then allows that same order SQL to be used to create an export file. I'm writing it for a piece of software that hosts basic user data in one table, and the question value I'm trying to get in another. Here's the details:
Table1 is base_user and from it I need the values of columns id, username, and email. However, I want to add the option to order/export by users with all that same data, but by their sex.
Table2 is base_question_data and from it I want to get the question 'sex' value.
Users can pick between Male or Female (Values: 1 or 2), and that info is stored in a column named intValue. I've already tried using INNER JOINS and such selecting multiple info from both tables, but where I'm getting confused is how to say "Get id, username, email, and sex for every user that is X sex" where "X sex" is the gender the user set to order/export by. I'm having a hard time figuring out how to get the specifics for the sex value for each user, but also use it to only show all those users of that value. All ideas are appreciated.
EDIT:
Forgot to mention that in the 'base_question_data' table, column 'userId' is equal to column 'id' in 'base_user' table.
This is Table1 or base_user
This is Table2 or base_question_data
To clarify what I'm trying to do:
In the 'base_user' table, I want to select ID, Username, and Email. I have this working normally, as it's a simple query. I want to, however, let users order by each user's gender. So
1)They can order the preview list by Male (questionName = sex intValue = 1) or Female (questionName = sex intValue = 2). This way, it will show all user's ID, Username, and Email who are gender 1 or 2. Using this same query, I'm trying to let them export that data as well, so they can export only users of gender 1 or 2.
My problem is the process of combining all of this data. I need to combine base_user's "id" to base_question_data's "userId" and I need to also get the value of each user by targeting base_question_data's questionName='sex' and get the intValue based on if they're ordering by Male (value=1) or Female (value=2).
I've done LEFT JOINS when combining one value to another for two tables, and while this is still two tables, I've never done it where I need to combine two different keys from two tables while also ordering them all by two different column values in one of those tables.
I agree with #rowmoin but if you use LEFT JOIN it will give null value if no entry in your base_question_data table and if you use INNER JOIN it will ignore those records from both tables which does not match so you can not get users from base_user if you do not have related entries in base_question_data table.
The query was easier than I anticipated. I will explain it in detail here.
To achieve something like this, (in which I needed one table's two values to decide what I'm getting in my other table results), I simply changed the value of 'intValue' in my query, but you can also do this by assigning a php value to let it be dynamically changed if you want. Since I'm doing a change between 1 or 2, I just have to different queries with the respective variable.
Here's my query:
SELECT * FROM ow_base_user
INNER JOIN ow_base_question_data ON ow_base_user.id = ow_base_question_data.userId
WHERE questionName='sex' AND intValue='$value';
I finally realized this morning I needed to go backwards, rather, and select my conditionals from base_question, rather than from the base_user table. Using this query, (where $value=1 for male or $value=2 for Female) I have successfully gotten to return a list of user's who match the set $value with their IDs, Username, and Email.

Perhaps joining 2 tables together when Users register

So this is my sorta first time doing an Online RPG (MMORPG), It's a browser based-Pokemon game.
In the Database, l've created 2 tables;
1.Pokemons (Columns; ID#, PokemonName, PokemonType, Level, Exp, HPoints, ATT, DEF)
2.Users (Columns; ID, Full Name, E-Mail, Username, Password)
In the Register field, they put in their info (User, Pass, Email), then chooses a Starter Pokemon to fight with. My question is how would i interpret that into a SQL/PHP command that joins the starter pokemon to that User or vise versa?
Far as l know it's
SELECT * FROM table_name;
But let's say l wanted to choose THAT user who just registered. Would the * just automatically choose that player or will it select everything from the Users list (Currently 3 rows of users in the Table).
Im reading w3schools for the moment, but needed some real-time advice on how l should go about with this. Thanks again!
thepokemonrpg.x10.mx If you guys wanna see what l mean.
This would indeed select everything from the Users table:
SELECT * FROM Users
The * doesn't mean all records, it just means all columns for any matching record. However, since there's no filter, all records happen to be matching records. If you want to only select a single record from that table, you would add a WHERE clause:
SELECT * FROM Users WHERE Username='someusername'
There are a few different ways that you can construct the SQL query to include a value like that (since someusername would likely come from a variable and not be explicitly written like that). Just be aware of SQL injection vulnerabilities when building those queries. You wouldn't want to accidentally publish a website where users can write their own database code and execute it on your server.
As for joining the tables, I currently don't see a way that you could do that. These two tables define two distinct entities, but have no way to relate to one another. There are a couple of ways you could do that, depending on how these entities are actually related. To that end:
Does a Pokemon always have exactly 0 or 1 owner? or;
Does a Person always have exactly 0 or 1 Pokemon? or;
Can a Pokemon have many owners and a Person have many Pokemons?
If the first statement is true, then you can add a UserId column to your Pokemons table and make it a foreign key to the Users table. That way every Pokemon record would indicate which User owns it.
If the second statement is true, then you can add a PokemonId column to your Users table and make it a foreign key to the Pokemons table. That way every User record would indicate which Pokemon is currently owns.
If the third statement is true, then you'd need to add a joining table to maintain this many-to-many relationship. Something like this:
PokemonUsers
------------
Id
PokemonId
UserId
Every record in this table would essentially be a link between a record in the Users table and a record in the Pokemons table.

Add database table from website

EDIT:Well I guess I should asked then before this question, would it be better to have a database full of tables(college names) that stores numbers than can be sorted in ascending order, or have a database with one table and select all the rows with the same "college name" and then sort the data from those rows after?
"
Is it possible to add a table in a database like...
CREATE TABLE table_name
(
column_name1 data_type,
column_name2 data_type,
column_name3 data_type,
....
)
...but call from a webpage instead of adding a table through mysql? So make a table in a database from code on my website?"
Yes you can send SQL queries through PHP.
Here is a resource that shows just what you're looking for I think
PHP MySQL Create Database and Tables
edit:
It depends on what you're doing, but I agree with the above comments that creating a table on page view is in most cases the wrong move.
If they all have the same basic structure I would put them all in the same table, and you can index the "college name" column. Reading from the database even with many many rows will still be quick, and if you decide to change something later you won't have to change X amount of tables.
You can also retrieve sorted results
SELECT * FROM Colleges WHERE name = 'University of Wisconsin' ORDER BY student_count ASC

What is the best approach to list a user's recent activities in PHP/MySQL?

I want to list the recent activities of a user on my site without doing too many queries. I have a table where I list all the things the user did with the date.
page_id - reference_id - reference_table - created_at - updated_at
The reference_id is the ID I need to search for in the reference_table (example: comments). If I would do a SELECT on my activity table I would then have to query:
SELECT * FROM reference_table where id = reference_id LIMIT 1
An activity can be a comment, a page update or a subscription. Depending which one it is, I need to fetch different data from other tables in my database
For example if it is a comment, I need to fetch the author's name, the comment, if it is a reply I need to fetch the orignal comment username, etc.
I've looked into UNION keyword to union all my tables but I'm getting the error
1222 - The used SELECT statements have a different number of columns
and it seems rather complicated to make it work because the amount of columns has to match and none of my table has the same amount of tables and I'm not to fond of create column for the fun of it.
I've also looked into the CASE statement which also requires the amount of columns to match if I remember correctly (I could be wrong for this one though).
Does anyone has an idea of how I could list the recent activities of a user without doing too many queries?
I am using PHP and MySQL.
You probably want to split out the different activities into different tables. This will give you more flexiblity on how you query the data.
If you choose to use UNION, make sure that the you use the same number of columns in each select query that the UNION is comprised of.
EDIT:
I was down-voted for my response, so perhaps I can give a better explanation.
Split Table into Separate Tables and UNION
I recommended this technique, because it will allow you to be more explicit about the resources for which you are querying. Having a single table for inserting is convenient, but you will always have to do separate queries to join with other tables to get meaningful information. Also, you database schema will be obfuscated by a single column being a foreign key for different tables depending on the data stored in that row.
You could have tables for comment, update and subscription. These would have their own data which could be queried on individually. If, say, you wanted to look at ALL user activity, you could somewhat easily use a UNION as follows:
(SELECT 'comment', title, comment_id AS id, created FROM comment)
UNION
(SELECT 'update', title, update_id as id, created FROM update)
UNION
(SELECT 'subscription', title, subscription_id as id, created
FROM subscription)
ORDER BY created desc
This will provide you with a listing view. You could then link to the details of each type or load it on an ajax call.
You could accomplish this with the method that you are currently using, but this will actually eliminate the need for the 'reference_table' and will accomplish the same thing in a cleaner way (IMO).
The problem is that UNION should be used just to get similar recordsets together. If you try to unify two different queries (for example, with different columns being fetched) it's an error.
If the nature of the queries is different (having different column count, or data types) you'll need to make several different queries and treat them all separately.
Another approach (less elegant, I guess) would be LEFT JOINing your activities table with all the others, so you'll end up with a recordset with a lot of columns, and you'll need to check for each row which columns should be used depending on the activity nature.
Again, I'd rather stick with the first one, since the second procudes a rather sparse recorset.
With UNION you don't have to get all of the columns from each table, just as long as all of the columns have the same datatypes.
So you could do something like this:
SELECT name, comment as description
FROM Comments
UNION
SELECT name, reply as description
FROM Replies
And it wouldn't matter if Comments and Replies have the same number of columns.
This really depends on the amount of traffic on your site. The union approach is a straightforward and possibly the correct one, logically, but you'll suffer on the performance if your site is heavily loaded since the indexing of a UNIONed query is hard.
Joining might be good, but again, in terms of performance and code clarity, it's not the best of ways.
Another totally different approach is to create an 'activities' table, which will be updated with activity (in addition to the real activity, just for this purpose). In old terms of DB correctness, you should avoid this approach since it will create duplicate data on your system, I, however, found it very useful in terms of performance.
[Another side note about the UNION approach if you decide to take it: if you have difference in parameters length, you can SELECT bogus parameters on some of the unions, for example.. (SELECT UserId,UserName FROM users) UNION (SELECT 0,UserName from notes)

Suggestions on retrieving related data across databases with different logins?

I have an array of user ids in a query from Database A, Table A (AA).
I have the main user database in Database B, Table A (BA).
For each user id returned in my result array from AA, I want to retrieve the first and last name of that user id from BA.
Different user accounts control each database. Unfortunately each login cannot have permissions to each database.
Question: How can I retrieve the firsts and lasts with the least amount of queries and / or processing time? With 20 users in the array? With 20,000 users in the array? Any order of magnitude higher, if applicable?
Using php 5 / mysql 5.
As long as the databases are on the same server just use a cross database join. The DB login being used to access the data will also need permissions on both databases. Something like:
SELECT AA.userID, BA.first, BA.last
FROM databasename.schema.table AA
INNER JOIN databasename.schema.table BA ON AA.userID = BA.userID
In response to comments:
I don't believe I read the part about multiple logins correctly, sorry. You cannot use two different mySQL logins on one connection. If you need to do multiple queries you really only have three options. A) Loop through the first result set and run multiple queries. B) Run a query which uses a WHERE clause with userID IN (#firstResultSet) and pass in the first result set. C) Select everything out of the second DB and join them in code.
All three of those options are not very good, so I would ask, why can't you change user permissions on one of the two DBs? I would also ask, why would you need to select the names and IDs of 20,000 users? Unless this is some type of data dump, I would be looking for a different way to display the data which would be both easier to use and less query intensive.
All that said, whichever option you choose will be based on a variety of different circumstances. With a low number of records, under 1,000, I would use option B. With a higher number of records, I would probably use options C and try to place the two result sets into something that can be joined (such as using array_combine).
I think they key here is that it should be possible in two database calls.
Your first one to get the id's from database A and the second one to pass them to database B.
I don't know mysql, but in sqlserver I'd use the xml datatype and pass all of the ids into a statement using that. Before the xml datatype I'd have built up some dynamic SQL with the id's in an IN statement.
SELECT UserId FROM DatabaseA.TableA
Loop through id's and build up a comma separated string.
"SELECT FirstName, Surname FROM DataBaseB.TableA WHERE UserId IN(" + stringId + ")"
The problem with this is that wth 20,000 id's you may have some performance issues with the amount of data you are sending. This is where'd I'd use the XML datatype, so maybe look at what alternatives mysql has for passing lists of ids.

Categories