Union alternate to make query more efficient. Mysql - mysql

Below is my query
Select
count(t.prid)
from
(select
pr.prid
from
jcp
inner join pr ON pr.prid = jcp.prid
where
jcp.custid = 123 union select
pr.prid
from
jcl
inner join pr ON pr.prid = jcl.prid
where
jcl.custid = 123) as t
is there any way to make it more efficient? this query is inside some function and executing 1000s of time. so making it slow.

First of all, your query appears to be combining two very different types of data in your 'union' - the first part being the count of an ID, and the second being the literal ID - so I would question whether this is really doing what you intend it to do as written. However, just taking it at face value, you could eliminate the subquery in the first part as follows:
SELECT COUNT(pr.prid)
FROM jcp
INNER JOIN pr
ON pr.prid = jcp.prid
WHERE jcp.custid = 123
I can't say how much that would help your performance without knowing the context of your data, but it certainly wouldn't hurt.
Given the difference in the two data sets, it doesn't appear possible to avoid the union if you want to force these two different bits of data into the same column. If you were to put them into different columns, you could probably avoid the union.

Related

Sql Join taking a lot of time

I am tying to execute this query but it is taking more than 5 hours, but the data base size is just 20mb. this is my code. Here I am joining 11 tables with reg_id. I need all columns with distinct values. Please guide me how to rearrange the query.
SELECT *
FROM degree
JOIN diploma
ON degree.reg_id = diploma.reg_id
JOIN further_studies
ON diploma.reg_id = further_studies.reg_id
JOIN iti
ON further_studies.reg_id = iti.reg_id
JOIN personal_info
ON iti.reg_id = personal_info.reg_id
JOIN postgraduation
ON personal_info.reg_id = postgraduation.reg_id
JOIN puc
ON postgraduation.reg_id = puc.reg_id
JOIN skills
ON puc.reg_id = skills.reg_id
JOIN sslc
ON skills.reg_id = sslc.reg_id
JOIN license
ON sslc.reg_id = license.reg_id
JOIN passport
ON license.reg_id = passport.reg_id
GROUP BY fullname
Please help me if I did any mistake
This is a bit long for a comment.
The first problem with your query is that you are using select * with group by fullname. You have zillions of columns in the select that are not in the group by. Unless you really, really, really know what you are doing (which I doubt), this is the wrong way to write a query.
Your performance problem is undoubtedly due to cartesian products and lack of indexes. You are joining across different dimensions -- such as skills and degrees. The result is a product of all the possibilities. For some people, the data size can grow and grow and grow.
And then, the question is: do you have indexes on the keys used in the joins? For performance, you generally want such indexes.
I thought the problem is in the query.First make sure group by fullname and try to give some column names instead of *.

Are indeces useful when using them in combination of an INNER JOIN?

I have three tables:
Orders
OrdersPromotions
Promotions
Most of my queries are of this kind:
SELECT `promotions`.* FROM `promotions` INNER JOIN `orders_promotions` ON `promotions`.`id` = `orders_promotions`.`promotions_id` WHERE `orders_promotions`.`orders_id` = 3 AND `promotions`.`code` = 'my_promotion_code'
So, I never fetch promotions directly, but also within the scope of an order. An order won't have many promotions. I am wondering if it would be useful to place an INDEX in the code column of promotion, knowing that when doing the INNER JOIN actually the results after the INNER JOIN are not many, and so, it would be ok to go through all them finding the promotion which code is the given.
Would an index make sense in my previous query, knowing that just this query:
SELECT `promotions`.* FROM `promotions` INNER JOIN `orders_promotions` ON `promotions`.`id` = `orders_promotions`.`promotions_id` WHERE `orders_promotions`.`orders_id` = 3
Would return no more than 20 rows?
You should almost always use an index on any fields you are going to use for joins, sorts, grouping, or filtering in where clauses. I would say ALWAYS, but there could be exceptions to the rule (like if you had a very heavy write load on a table that was very infrequently used for reads where indexes would be useful).

Select taking too long. Need advice for a better performance

Ok, here we go. There's this messy SELECT crossing other tables and ordering to get the one desired row. Basically I do the "math" inside the ORDER BY.
1 base table.
7 JOINS poiting to local tables.
WHERE with 2 clauses and a NOT IN crossing another table.
You'll see in the code the ORDER BY is pretty damn big/ugly, it sums the result of 5 different calculations. I need that result to order by those calculations in order to get the worst row-case.
The problem is once I execute the Stored Procedure it takes up to 8 seconds to run. That's kind of non-acceptable. So, I'm starting to check Indexes.
So, I'm looking for advices on how to make this query run faster.
I'm indexing the WHERE clauses and the field LINEA, Should I index something else? Like the rows Im crossing for the JOINs? or should I approach the query differently?
Query:
SET #LINEA = (
SELECT TOP 1
BOA.LIN
FROM
BAND_BA BOA
LEFT JOIN
TEL PAR
ON REPLACE(BOA.Lin,'-','') = SUBSTRING(PAR.Te,2,10)
LEFT JOIN
TELP CLP
ON REPLACE(BOA.Lin,'-','') = SUBSTRING(CLP.Numtel,2,10)
LEFT JOIN
CA C
ON REPLACE(BOA.Lin,'-','') = C.An
LEFT JOIN
RE R
ON REPLACE(BOA.Lin,'-','') = R.Lin
LEFT JOIN
PRODUCTOS2 P2
ON BOA.PRODUCTO = P2.codigo
LEFT JOIN
EN
ON REPLACE(BOA.Lin,'-','') = EN.G
LEFT JOIN
TIP ID
ON TIPID = ID.ID
WHERE
BOA.EST = 'C' AND
ID.SE = 'boA' AND
BOA.LIN NOT IN (
SELECT
LIN
FROM
BAN
)
ORDER BY (EN.VALUE + ANT.VALUE + REIT.VAL + C.VALUE + TEL.VALUE
) DESC,
I'll be frank, this is some pretty terrible SQL. Without seeing all your table structures, advice here will be incomplete. That being said, please don't post all your table structures because you are already very close to "hire a consultant" territory with this.
All the REPLACE logic should be done away with. If you need to JOIN on these fields, then add comparable fields to the tables so you don't need to manipulate the data. Every single JOIN that uses a REPLACE or SUBSTRING is a table or index scan - those are non-SARGable and a definite anti-pattern.
The ORDER BY is probably the most convoluted ORDER BY I have ever seen. Some major issues there:
Subqueries should all be eliminated and materialized either in the outer query or as variables
String manipulation should be eliminated (see item 1 above)
The entire query is basically a code smell. If you need to write code like this to meet business requirements then you either have a terribly inappropriate design or some other much larger issue in the organization or data.
One thing that can kill performance is using a lot of LEFT JOINs. To improve performance of LEFT JOIN, you might want to make sure that the column(s) to which you join have an index - that can have a huge impact on performance.

MySQL - Fix multiple records

SELECT cf.FK_collection, c.collectionName,
uf.FK_userMe, uf.FK_userYou,
u.userId, u.username
FROM userFollows as uf
INNER JOIN collectionFollows as cf ON uf.FK_userMe = cf.FK_user
INNER JOIN collections as c ON cf.FK_collection = c.collectionId
INNER JOIN users as u ON uf.FK_userYou = u.userId
WHERE uf.FK_userMe = 2
Hey guys.
I'm trying to make this query, and it of course won't do as I want it to, since it's returning multiple rows which is in some way what I want, and yet it's not. Let me try to explain:
I trying to get both collectionFollows and userFollows, for showing a users activity on the site. But when doing this, I will have multiple rows from userFollows even tho a user only follows 1. This occurs because I'm following multiple collectionFollows.
So when I show my result it will return like this:
John is following 'webdesign'
John is following 'Lisa'
John is following 'programming'
John is following 'Lisa'
I would like to know if I have to make multiple queries or use an subquery? What would be best practice? And how would I write the query then?
You are actually combining two quite unrelated queries. I would keep them as separate queries, especially since you report them like that too. You could, if you like, use UNION ALL to combine those queries. This way, you have just a list of names of items you follow, regardless of the type of item it is. If you want, you can specify that too.
SELECT
cf.user,
cf.FK_collection as followItem,
c.collectionName as followName,
'collection' as followType
FROM collectionFollows as cf
INNER JOIN collections as c ON cf.FK_collection = c.collectionId
WHERE cf.user = 2
UNION ALL
SELECT
uf.FK_userMe,
u.userId,
u.username
'user' as followType
FROM userFollows as uf
INNER JOIN users as u ON uf.FK_userYou = u.userId
WHERE uf.FK_userMe = 2
An alternative would be to filter unique values in PHP, but even then your query will fail. Because of the inner joins, you will not get any results if a user only follows other users or only follows collections. You need at least one of both to get any results.
You could change INNER JOIN to LEFT JOIN, but then you would still have to post-process the query to filter doubles and filter out the NULL values.
UNION ALL is fast. It just sticks two query results together without furthes processing. This is different from UNION, which will filter double as well (like DISTINCT). In this case, it is not needed, because I assume a user can only follow a collection or other user once, so these queries will never return duplicate records. If that is indeed the case, UNION ALL will do just fine and will be faster than UNION.
Apart from UNION ALL, two separate queries is fine too.

Why does this query make my whole database freeze?

SELECT * FROM `groupon-spain-6sep-2011`, `Hoja1`,`GroupaliaJuly2011`
WHERE `groupon-spain-6sep-2011`.`code`= 5654
OR `Hoja1`.`code` = "5654
OR `GroupaliaJuly2011`.`code` = 5654
You are missing any join condition relating the tables to each other so are doing a cartesian join of 3 tables.
I recommend always using explicit join syntax
SELECT *
FROM `groupon-spain-6sep-2011`
JOIN `hoja1` ON `groupon-spain-6sep-2011`.foo=`hoja1`.foo
JOIN `groupaliajuly2011` ON `groupaliajuly2011`.`foo` = `hoja1`.foo
WHERE `groupon-spain-6sep-2011`.`code` = 5654
OR `hoja1`.`code` = 5654
OR `groupaliajuly2011`.`code` = 5654
Although it is possible that you might be wanting a Union here I think anyway?
You might want to do a union instead:
SELECT *
FROM groupon-spain-6sep-2011
WHERE code = 5654
UNION SELECT *
FROM Hoja1
WHERE code = 5654
UNION SELECT *
FROM GroupaliaJuly2011
WHERE code = 5654
The query you posed involves the Cartesian product(also known as CROSS JOIN in standard SQL, thanks for the advice #onedaywhen) of three tables, the amount of record involves will be size(A) * size(B) * size(C). So if the total product is large enough, it will fill a significant amount of memory, which will make your database unable to response to any other request, and that will lead to the 'freeze' of your database.
I noticed that you want either of the three specified columns to be the same value '5654', so you can selet tuples from three table respectively, and then UNION them, instead of doing Cartesian product of them like you're doing it now, since I don't think the Cartesian product you're making makes any sense. That will save a GREAT number of memory.