SQL statement that hangs DB - mysql

I was trying to cross reference 2 tables using the following query from myPhpAdmin app:
select A.*
from purchases A
where A.user in (
select B.user
from users B
where B.ppi = 'Facebook Ads'
)
It accepted the syntax but the DB never returned. The users table is not small, 200k rows, but i run querys on it all the time so it shouldn't take that long.. Any ideas as to why this might not work? The query was stuck in the state:Sending data. I had to kill it because my database was broken at this point so I cannot run any other checks on this now and Im scared to try again :)
Running on mysql FYI.
What I really wanted was just to be able to operate on values in table purchases only when the same user id is present in the other table with the given ppi value.

Use a join and make sure, you have indices on B.user and B.ppi.
SELECT A.*
FROM purchases A
INNER JOIN users B ON A.user=B.user
WHERE B.ppi = 'Facebook Ads'

A join should be faster than a subquery. Try this:
Select A.* from purchases A
INNER JOIN users B on A.user = B.user
WHERE B.ppi='Facebook Ads'

Related

MySql Query Timed Out in Live but not in Local

We are using MySQL InnoDB.
We have a query looks like this.
In our live environment, this query took more than 30 seconds to complete.
select count(*) as aggregate
from `parents`
where exists (
SELECT *
from `childs`
where `parents`.`id` = `childs`.`parent_id`
and exists (
SELECT *
from `users`
where `childs`.`user_id` = `users`.`id`
and `id` = '123456' )
and `status` = 'OK' )
And so we have exported the whole database and import into to our local mysql database.
And surprisingly, it took almost instant to get the same query results.
As so we suspect the table was not optimized and we have done the following.
optimize table users;
optimize table parents;
optimize table childs;
Unfortunately the query speed didn't improve.
Can anyone see what could goes wrong?
And why does export/import in local (with exactly same structure data) have almost instant query and the live took almost 30-60 seconds to complete?
EXPLAIN on both local and live shows a difference,
one of the DEPENDENT SUBQUERY for possible keys relating the parents and child table shows
Using where; FirstMatch(closing_batches)
but the live shows only Using where without the FirstMatch.
You can actually probably get all the data from a single query without even using the parents or user table -- IF the "Status" field is in the childs table.
From basic Transitive association,
if A = B and B = C, then A = C.
You are joining from Child to User by ID, then looking at the User ID = "123456".
This is the same as just asking for Childs.User_ID = "123456".
Likewise, from the Child joined to the parent by the Child.Parent_ID, it looks like your query is trying to get a count of distinct parent IDs that are associated with given childs.
So, the following SHOULD be able to get what you need.
select
count( distinct c.Parent_id ) Aggregate
from
childs c
where
c.user_id = '123456'
AND c.status = 'OK'
if the status field is on the PARENT table, you will need to join to that
select
count( distinct c.Parent_id ) Aggregate
from
childs c
join parents p
on c.parent_id = p.id
AND p.status = 'OK'
where
c.user_id = '123456'
For performance, I would ALSO have an index on the childs table on ( user_id, parent_id ). This can significantly optimize the query too.
This is probably equivalent:
select count(*) as aggregate
from `parents` AS p
where exists (
SELECT *
from `childs` AS c
JOIN users AS u ON c.user_id = u.id
WHERE c.user_id = 123456
AND p.`id` = c.`parent_id`
and `status` = 'OK'
)
OPTIMIZE TABLE is rarely useful.
Which table is status in?

SQL check if thread timestamp is newer than reply timestamp in JOIN Statement

So I'm kinda new to SQL joins and was thinking on going full overkill probably.
What I want to do is join my four tables together.
What I want to accomplish is that I want all the information from category, and I want it to be matched to the replies with the newest timestamp and then I want to join the t.title which t.id matches r.thread_id
SELECT c.*, t.id, t.title, r.timestamp, u.id, u.username
FROM forum_category AS c
LEFT JOIN forum_threads AS t ON (c.id = t.category_id)
LEFT JOIN forum_replies AS r ON (t.id = r.thread_id
AND r.timestamp =
(
SELECT timestamp
FROM forum_replies
ORDER BY timestamp DESC LIMIT 1
))
LEFT JOIN users AS u ON (r.user_id = u.id)
GROUP BY c.id
As it is now this code seems to work, not having tested it alot.
However I need to expand it to check if t.timestamp is newer than latest r.timestamp and JOIN that one instead then. with the t.title, t.timestamp and t.user_id.
So if a thread is newer than the latest reply.
I know I could make the first post a reply and solve it that way. But I'm not doing that right now if it's possible to solve in the SQL statement.
SQL layout imgur here:
https://imgur.com/a/nCn2a
forum_category:
forum_threads:
forum_replies:
One helpful technique is to use Subqueries to break up the mental logic of what your query is trying to do. Basically, a subquery takes the place of a regular table in any query.
So, first up, we need to get the most recent time stamp in the replies for each thread:
select thread_id, max(timestamp) as LatestReply
from forum_replies
group by thread_id
Let's call this our MostRecentThreadSubquery. So, it would let us do something like:
select * from
forum_threads t
LEFT JOIN
(
select thread_id, max(timestamp) as LatestReply
from forum_replies
group by thread_id
) as MostRecentThreadSubquery
on t.thread_id = MostRecentThreadSubquery.thread_id
Make sense? We're no longer joining the forum_threads table against the forum_replies table - we've made a subquery to help us list the most recent reply for each thread id.
Now, we add the SQL CASE statement, to get something like:
select
thread_id,
CASE WHEN t.timestamp > MostRecentThreadSubquery.LatestReply
THEN t.timestamp
ELSE MostRecentThreadSubquery.LatestReply
END as MostRecentTimestamp
from -- ... the rest of that earlier SQL statement
Okay, so now we've got a query that, for every thread_id, has the most recent timestamp - whether that's from the forum_replies or from the forum_threads table.
... and you guessed it. We're going to make it another subquery. Let's call it our MostRecentPerThread
select *
from forum_category AS c
LEFT JOIN
(
-- ... that previous query ...
) as MostRecentPerThread
on c.thread_id = MostRecentPerThread.thread_id
Make sense? You're using subqueries as a way of logically breaking down your query into smaller components. You no longer have one gigantic query. You've got a small subquery that simply gets the timestamp of the most recent reply. You've got a small subquery that compares that first subquery to the threads table to get the most recent timestamp. And you've got a main query that uses the second subquery to merge it with the categories table.

SQL to show even null record

Below is my sql statement
SELECT a.purchase_id,
b.username,
a.purchase_packageid,
a.purchase_tradelimit,
a.purchase_pincode,
a.purchase_datetime,
c.packages_name ,
FROM purchase a,
accounts b,
packages c
WHERE a.purchase_userid=b.UserId
AND c.packages_id=a.purchase_packageid
Basically the issue is I got 3 tables
Accounts
Purchase
Packages
The main table is Purchase, inside the table there is purchase_userid , which I need to use it to get username from table accounts
So the problem now is I got rows where the purchase_userid is blank, because its blank, it won't draw its record as null.
The only record that show in this sql statement is only those with purchase_userid,
As the value for purchase_userid will be fill up later for my web app,
I still want to select rows without purchase_userid and those with purchase_userid
Thanks for helping !!
You need to use a left join to load all records in Purchase even when no matching records are found in Accounts.
SELECT a.purchase_id, b.username, a.purchase_packageid, a.purchase_tradelimit, a.purchase_pincode, a.purchase_datetime, c.packages_name
FROM purchase a LEFT JOIN accounts b
ON a.purchase_userid=b.UserId
JOIN packages c
ON c.packages_id=a.purchase_packageid
This post explains the different kinds of joins pretty well: What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?
You're using the old-timey syntax for INNER JOINs between your tables, when what you need is LEFT JOIN operations. Try this:
SELECT a.purchase_id,
b.username,
a.purchase_packageid,
a.purchase_tradelimit,
a.purchase_pincode,
a.purchase_datetime,
c.packages_name
FROM purchase AS a
LEFT JOIN accounts AS b ON a.purchase_userid = b.UserId
LEFT JOIN packages AS c ON a.purchase_packageid = c.packages_id
This works better for you because the kind of JOIN you were using suppresses records from your a table when they weren't matched in your b or c table. This LEFT JOIN will leave the a table records in place, and put NULL values where you are calling for data from the other two.

Inner join works Too Slower - just show loading label in phpmyadmin

I have 3 tables each have almost 70,000 data
when i execute select query in which i add one inner join than it works faster.
Following works faster
select A.id from product as A
inner join product_cat as B on A.id=B.mapped_id
OR
select A.id from product as A
inner join product_sup as C on A.id = C.mapped_id
(It works faster for one inner join)
but when i add both inner join in same select query than it works too slower(Does not display data it just show loading label in phpmyadmin)
select A.id
from product as A
inner join product_cat as B
on A.id = B.mapped_id
inner join product_sup as C
on A.id = C.mapped_id
my purpose it only to find out how much record is there in database.
also tried with count function though takes too much time.
Any help will be appreciated,
Thanks,
Use EXPLAIN to analyze performance of the query and identify any missing indexes.
http://dev.mysql.com/doc/refman/5.5/en/using-explain.html
http://dev.mysql.com/doc/refman/5.5/en/explain-output.html
Add your actual query, execution plan printed by EXPLAIN and CREATE TABLE statements of all involved tables to your question if you want to get a specific advice.
Maybe your query is trying to return more than 1 million of result and that is the reason fo the slowness. Maybe you are doing a Cartesian product between tables B and C.
Let's put an example.
Table (A) = (id=1)
Table (B) = (id=1,mapped_id=1),(id=2,mapped_id=1),
(id=3,mapped_id=1),(id=4,mapped_id=1)
Table (C) = (id=1,mapped_id=1),(id=2,mapped_id=1), (id=3,mapped_id=1)
If we do that query with those data it would return 12 rows, all of them with A.id=1
To solve the problem you could try to use a DISTINCT on the SELECT clause or to do a group with the GROUP BYclase, but I think the better solution is to redesing the query depending on your goals.
If you want to use the group by your query will be something like this
select A.id from product as A
inner join product_cat as B on A.id = B.mapped_id
inner join product_sup as C on A.id = C.mapped_id
group by A.id

MySQL IN clause is too slow, cannot get JOIN to work properly

I have a little problem that I cannot wrap my head around.
This query does exactly what I need, only it takes forever and just kills mysql daemon.
"SELECT *
FROM inventory
WHERE
mac LIKE '%".$s."%'
OR uid IN (SELECT id FROM clients WHERE username LIKE '%".$s."%')"
The proper way is to go with JOIN clause but unfortunately I cannot get it to work.
Basically, I'm trying to search two tables and then choose records either based on mac-address or username.
Any help would be appreciated!
Here's one approach:
"SELECT i.*
FROM inventory i
LEFT
JOIN ( SELECT c.id
FROM clients c
WHERE c.username LIKE '%".$s."%'
GROUP BY c.id
) v
ON v.id = i.uid
WHERE i.mac LIKE '%".$s."%'
OR v.id IS NOT NULL"
This should be significantly more efficient than re-executing the IN (subquery) for each and every row in the inventory table. But the query is still problematic, in that it has to perform a full scan of every row in both the inventory and clients tables.
SELECT inventory.*
FROM inventory LEFT JOIN clients ON (inventory.uid=clients.id)
WHERE
mac LIKE '%".$s."%' OR username LIKE '%".$s."%'