Fetching few records from mysql database having million entries - php

I have a table which has million rows. It has user id as its primary key. I have an array having 500 user ids in it.
I want to select all the records from the table whose user ids are in the array. I know one method to do this is to change the array into a string and run IN query by passing the string.
But I think it is not the efficient way to do it. So kindly suggest other ways.

I am assuming that your ids are integer. Maybe you are getting this list of Ids from some other sources so that a join on mysql side is not desired solution. If yes, then find the maximum and minimum id present in your 500 Ids list. You can do this in php side. When you have the max and min value, then query mysql db with a where clause
select ...
from table_name
where min_id <= id and id <= max_id
id is the primary key so the advantage is that it is already indexed.

I have done this in the past, I am not sure that my method is the most efficient.
I create a string out of the ids: where id = a or id = b or id = c ...
then I add the select statement in front of it, and do a fetchall.

My guess is that you're getting these user IDs from another table and that you are storing them in an array. If this is correct, then you should change the query that fetches these user IDs so that it uses a join instead.

Joins will help you there, because IN() is not a good programming practice.
You can learn about joins here : http://mysqljoin.com/

Related

Check if row exists, The most efficient way?

SQL Queries /P1/
SELECT EXISTS(SELECT /p2/ FROM table WHERE id = 1)
SELECT /p2/ FROM table WHERE id = 1 LIMIT 1
SQL SELECT /P2/
COUNT(id)
id
PHP PDO Function /P3/
fetchColumn()
rowCount()
From the following 3 Parts, What is the best method to check if a row exists or not with and without the ability to retrieve data like.
Retrievable:
/Query/ SELECT id FROM table WHERE id = 1 LIMIT 1
/Function/ rowCount()
Irretrievable
/Query/ SELECT EXISTS(SELECT COUNT(id) FROM table WHERE id = 1)
/Function/ fetchColumn()
In your opinion, What is the best way to do that?
By best I guess you mean consuming the least resources on both MySQL server and client.
That is this:
SELECT COUNT(*) count FROM table WHERE id=1
You get a one-row, one-column result set. If that column is zero, the row was not found. If the column is one, a row was found. If the column is greater that one, multiple rows were found.
This is a good solution for a few reasons.
COUNT(*) is decently efficient, especially if id is indexed.
It has a simple code path in your client software, because it always returns just one row. You don't have to sweat edge cases like no rows or multiple rows.
The SQL is as clear as it can be about what you're trying to do. That's helpful to the next person to work on your code.
Adding LIMIT 1 will do nothing if added to this query. It is already a one-row result set, inherently. You can add it, but then you'll make the next person looking at your code wonder what you were trying to do, and wonder whether you made some kind of mistake.
COUNT(*) counts all rows that match the WHERE statement. COUNT(id) is slightly slower because it counts all rows unless their id values are null. It has to make that check. For that reason, people usually use COUNT(*) unless there's some chance they want to ignore null values. If you put COUNT(id) in your code, the next person to work on it will have to spend some time figuring out whether you meant anything special by counting id rather than *.
You can use either; they give the same result.

INSERT INTO table SELECT not giving correct last_id

I have 2 tables with similar columns in MYSQL. I am copying data from one to another with INSERT INTO table2 SELECT * FROM table1 WHERE column1=smth. I have different columns as autoincrement and KEY in tables. When I use mysqli_insert_id i get the first one rather then last one inserted. Is there any way to get the last one?
Thanks
There is no inherit ordering of data in a relational database. You have to specify which field it is that you wish to order by like:
INSERT INTO table2
SELECT *
FROM table1
WHERE column1=smth
ORDER BY <field to sort by here>
LIMIT 1;
Relying on the order a record is written to a table is a very bad idea. If you have an auto-numbered id on table1 then just use ORDER BY id DESC LIMIT 1 to sort the result set by ID in descending order and pick the last one.
Updated to address OP's question about mysqli_insert_id
According to the Mysql reference the function called here is last_insert_id() where it states:
Important If you insert multiple rows using a single INSERT statement,
LAST_INSERT_ID() returns the value generated for the first inserted
row only. The reason for this is to make it possible to reproduce
easily the same INSERT statement against some other server.
Unfortunately, you'll have to do a second query to get the true "Last inserted id". Your best bet might be to run a SELECT COUNT(*) FROM table1 WHERE column1=smth; and then use that count(*) return to add to the mysqli_insert_id value. That's not great, but if you have high volume where this one function is getting hit a lot, this is probably the safest route.
The less safe route would be SELECT max(id) FROM table2 or SELECT max(id) FROM table2 Where column1=smth. But... again, depending on your keys and the number of times this insert is getting hit, this might be risky.

Adding a Row into an alphabetically ordered SQL table

I have a SQL table with two columns:
'id' int Auto_Increment
instancename varchar
The current 114 rows are ordered alphabetically after instancename.
Now i want to insert a new row that fits into the order.
So say it starts with a 'B', it would be at around id 14 and therefore had to 'push down' all of the rows after id 14. How do i do this?
An SQL table is not inherently ordered! (It is just a set.) You would simply add the new row and view it using something like:
select instancename
from thetable
order by instancename;
I think you're going about this the wrong way. IDs shouldn't be changed. If you have tables that reference these IDs as foreign keys then the DBMS wouldn't let you change them, anyway.
Instead, if you need results from a specific query to be ordered alphabetically, tell SQL to order it for you:
SELECT * FROM table ORDER BY instancename
As an aside, sometimes you want something that can seemingly be a key (read- needs to be unique for each row) but does have to change from time to time (such as something like a SKU in a product table). This should not be the primary key for the same reason (there are undoubtedly other tables that may refer to these entries, each of which would also need to be updated).
Keeping this information distinct will help keep you and everyone else working on the project from going insane.
Try using an over and joining to self.
Update thetable
Set ID = r.ID
From thetable c Join
( Select instancename, Row_Number() Over(Order By instancename) As ID
From CollectionStatus) r On c.instancename= r.instancename
This should update the id column to the ordered number. You may have to disable it's identity first.

Return all records of non-given id if just one of those records matches the given id of another field

After searching for a damn long time, I've not found a query to make this happen.
I have an "offers" table with a "listing_id" field and a "user_id" field and I need to get ALL the records for all listing_id's where at least one record matches the given user_id.
In other words, I need a query that determines the listing_id's that the given user is involved in, and then returns all the offer records of those listing_id's regardless of user_id.
That last part is the problem. It's getting all the other user's offer records to return when I'm only providing one user's id and no listing id's
I was thinking of first determining the listing_ids in a separate query and then using a php loop to create a WHERE clause for a second query that would consist of a bunch of "listing_id = $var ||" but then I couldn't bring myself to do it because I figured there must be a better way.
Hopefully this is easy and the only reason it has escaped me is because I've had my head up my ass. Will be happy to get this one behind me.
Thanks for taking the time.
Josh
You could do two queries playing along on the MySQL side, like this:
SELECT * FROM offers WHERE listing_id IN (SELECT listing_id FROM offers WHERE user_id = 1)
If I understand what you are after you should join offers on itself on listingid match and userid = given
select * from offers AS t1
inner join offers AS t2 on t1.listingid = t2.listingid and t1.userid = 1;

Multiple 'Select column where ...' vs Select all the column

I have to select 4 rows randomly from a column.
Is is better to generate randomly 4 id and to perform 4 requests 'select column from database where id = ... '
Or to select all the rows in one request and to choose after?
If you are capable of generating random existing id's, I think the best approach is to use a clause like where id in (id1, id2, id3, id4). This will result in getting 4 records in one query, so no unnecessary query's or records are fetched.
As told before, where id in (id1, id2, id3, id4) is the fastest way from the MySQL perspective. How ever, you will need some logic in the application generating those IDs : All 4 IDs shall exist, be randomly distributed, and you want to avoid duplicates. In worst case you will be retrieving a list of all existend IDs with a huge query, extracting 4 random values, and querying again.
With all that logic to be done, it can be wise to move selection into MySQL:
SELECT * FROM foobar
ORDER BY RAND()
LIMIT 4;
You must understand that this is slow in mysql, but you have a speed gain in the application logic and can be sure to get random values equally seed all over your table.
EDIT:
The comment asks if PHP is fasten in this task then MySQL. Answer is no.
It is not done by "using rand". You need to have an array containing all those IDs in PHP. That is a huge query, lots of TCP traffic, huge array to be buildt in php, huge btree to be buildt by zend engine. Then, with the IDs, you must fire a second query to get the rows for those IDs.
Although the RAND() function may be slow, so far I have not had significant problems with speed. MY strategy is actually to join the database back to a query of itself returning a list of random IDs with a limit.
SELECT *
FROM table AS t1
JOIN (
SELECT rowID
FROM table
ORDER BY RAND()
LIMIT 4
) AS t2
WHERE t1.rowID = t2.rowID
There is also a more robust solution that exist - try checking out this question (asked in 2010).

Categories