I have two tables in a MySQL database that I can't seem to work with very efficiently. The first is a payments table with around 25,000 rows and the following fields.
ID, Email, Type
The second is a users table which has 2,000 rows and the following:
ID, Email, AccessDate
Using the MySQL JOIN statement I have put this together, and it works perfectly:
UPDATE users INNER JOIN payments ON users.Email=payments.Email SET
AccessDate=NOW() WHERE payments.Type='success'
The problem is, it takes about 95 seconds to execute the query on a local machine. Any tips on how I might get around this speed issue?
Firstly you can use EXPLAIN to see what the optimiser is doing. You`ll have to reconstruct the code to be a SELECT:
EXPLAIN SELECT * FROM users INNER JOIN payments ON users.Email=payments.Email WHERE payments.Type='success'
Most likely is that the join has no index it can use. Does "ID" have an Index? Perhaps you can add that to the Join clauses? Or possibly add indexes for the "Email" column on both tables?
Related
I have PHP system that runs a MYSQL query like below
select
order.id,
order.name,
order.date,
customer.name,
items.coupon_code,
from order
left join customer on order.custid = customer.id
left join items on items.coupon_code = order.coupon_code
where items.coupon_new_code is null
and order.status = 1000
AND order.promo_code in (1,2)
order table has 800K records and items table has 300k records. When I run this the query takes about 9 hours to finish!
If I comment the left join to the items table then the query runs in a few seconds! I am not very efficient with MySQL joins and would really really appreciate if someone can tell me how I can optimise this query to run in an acceptable time frame.
Try changing
LEFT JOIN to INNER JOIN (or just JOIN)
This will work to speed things up assuming that you only want to see orders that have both customers and items associated with them. Currently your query is trying to return all data from the order table but that's not needed. It's possible other changes to the database structure could improve things as well.
The top answer here provides a useful diagram that demonstrates the difference between these types of statements.
At the very least you need an index on coupon_code on both order and items tables. Consider also adding to a compound index, the other field you are joining on custid, as well as on your WHERE conditions items.coupon_new_code, order.status and order.promo_code. Knowing next to nothing about your data I can only speculate about what the dbms will use. Try various combinations in a compound key and run explain to see what's being used. It's really going to depend on the specificity of the data in your columns.
Posting the output of EXPLAIN along with the tables' schema will help us improve these answers.
I need to update several columns in one table, based on columns in another. To start with I am just updating one of them. I have tried 2 ways of doing this, which both work, but they are taking about 4 minutes using mySQL commands, and over 20 when run in php. Both tables are about 20,000 rows long.
My question is, is there a better or more efficient way of doing this?
Method 1:
UPDATE table_a,table_b
SET table_a.price = table_b.price
WHERE table_a.product_code=table_b.product_code
Method 2:
UPDATE table_a INNER JOIN table_b
ON table_a.product_code = table_b.product_code
SET table_a.price=table_b.price
I guess that these basically work in the same way, but I thought that the join would be more efficient. The product_code column is random text, albeit unique and every row matches one in the other table.
Anything else I can try?
Thanks
UPDATE: This was resolved by creating an index e.g.
CREATE UNIQUE INDEX index_code on table_a (product_code)
CREATE UNIQUE INDEX index_code on table_b (product_code)
If your queries are running slowly you'll have to examine the data that query is using.
Your query looks like this:
UPDATE table_a INNER JOIN table_b
ON table_a.product_code = table_b.product_code
SET table_a.price=table_b.price
In order to see where the delay is you can do
EXPLAIN SELECT a.price, b.price FROM table_b b
INNER JOIN table_a a ON (a.product_code = b.product_code)
This will tell you if indexes are being used, see the info on EXPLAIN and more info here.
In your case you don't have any indexes (possible keys = null) forcing MySQL to do a full table scan.
You should always do an explain select on your queries when slowness is an issue. You'll have to convert non-select queries to a select, but that's not difficult, just list all the changed fields in the select clause and copy join and where clauses over as is.
I have a list of subscribers in table Subscribers. Every time they receive a copy of their subscription, a new record is created in Subscriptions_Fulfilments for each Subscribers.ID.
I can create a table showing each Subscriber ID and the number of copies they received with the following query:
SELECT Sub_ID, COUNT(Sub_ID) fcount FROM `Subscriptions_Fulfilments`
GROUP BY Sub_ID
But I need to create a compound query that returns Subscribers along with a column showing the COUNT(Sub_ID) of Subscriptions_Fulfilments.
So I have two questions:
A) How would you make a query to create a table that shows each Subscriber and the number of times they've received their subscription, based on the COUNT of that Subscriber's ID in Subscriptions_Fulfilments?
B) I'm operating under the assumption that a single MySql query accomplishing this would be more efficient than, say, running two queries, the one above and a SELECT * FROM Subscriptions, and combining the resulting arrays in PHP. I have a feeling I know the answer but I'd like to positively learn something new today.
Unfortunately, after too many tries, I'm clearly not good enough at queries for this and I have very little past the above query to show for it. I apologize if this ends up being a dup, I searched long and hard before asking, but it's quite difficult to search precisely for Query help...
Here is a simple example showing the Subscribers ID and the no of subscription they have received. Hope it helps.
Step 1: select the ids from the Subscriber table
Step 2: select the no of counts of subscriptions received by each subscriber.
Step 3: Join both the table ON the basis of ID.
SELECT SubId, noSub FROM
Subscribers sb JOIN (SELECT SubId AS sid, COUNT(*)AS noSub FROM Subscriptions_Fulfilments GROUP BY SubId)AS ss ON sb.SubId = ss.sid
One of the big advantages of a relational database is the ability to do joins and combinations of the data in your tables in a way that allows for this functionality without having to actually store it in a separate table.
You can accomplish this with a subquery like this:
SELECT Subscribers.name, fulfilments.count FROM Subscribers
INNER JOIN (
SELECT id, count(*) as count FROM Subscriptions_Fulfilments
GROUP BY Sub_Id
)fulfilments ON subscribers.id = fulfilments.id
This might not be 100% what you're looking for and I might have messed up your names, but hopefully this will start to get you in the neighborhood of being correct?
Simply try execute this query:
Select distinct Sub_ID, count from (SELECT Sub_ID, COUNT(Sub_ID) fcount FROM Subscriptions_Fulfilments
GROUP BY Sub_ID);
I have two database tables one called clients, the other one users. I'm trying to select single field "email" from both tables. Note, that email field is in both tables.
Table clients contains 10 records, while users has 5 records.
The below query works, but for some reason records are repetitive, so instead of getting 15 records in total, I end up with 50. Seems like records from one table are multiplied by records from other table.
SELECT
clients.email,
users.email
FROM
clients,
users;
Any help would be appreciated.
Your query returns cartesian product
You can simply use union all
select email from clients
union all
select email from users
You are getting 50 rows because cross join is happening there, go for inner join or left join or right join as per your choice, most preferably inner join...
Take some common attributes in both like id or something...
select clients.email, users.email from clients,users where clients.id=users.id...
try renaming the fields
For Clients table
clients_email
For Users table
users_email
then query as
SELECT clients.clients_email, users.users_email FROM clients, users WHERE clients.clients_email = users.users_email;
Hope it helps
I'm having trouble with a join query, my issue is as follows.
Table: battles
Fields: id,attacker_id,defender_id
Table: users
Fields: id,profile_image
I would like to do a query to retrieve a battle and get the profile images as well from the other table.
Is there a way to do this in a single or do I have to do more than one?
Thanks in advance.
I wanted to wait a while to see if you had any attempt or if you will answer my first question to know if I understood the problem. But maybe you don't have a starting point. Try something like:
SELECT
a.profile_image as attacker_profile_image,
d.profile_image as defender_profile_image
FROM
`battles` b
LEFT JOIN
`users` a
ON
b.`attacker_id` = a.`id`
LEFT JOIN
`users` d
ON
b.`defender_id` = d.`id`
the problem here is the fact that you need to join with the users table twice, so you will need to create aliases for the columns you plan to use
This query will fetch the two images only, you will need to add the extra fields