How do I optimize these SQL queries? - mysql

I have 1 variable which is used as WHERE condition in 3 initial queries. Based on the response from one of those I need to create queries to 2 more queries.
$var1 = $_GET['id']; $var2 = $_GET['truck'];
//first two are easy
SELECT `name`, `address` FROM `company` WHERE `id`='".$var1."' LIMIT 1; //q1
SELECT `value`, `date` FROM `checks` WHERE `truck`='".$var2."'; //q2
//the 3rd query may have multiple results and for every result i need **q4** and **q5** to be executed
SELECT `loadNumber`, `cfnNumber` FROM `loads` WHERE `truck`='".$var2."' ; //q3
//notice that WHERE conditions use values from **q3**
SELECT `value`, `date` FROM `finances` WHERE `load`='".loadNumber."'; //q4
SELECT `address` FROM `stops` WHERE `load`='".loadNumber."'; //q5
My question is about optimization as I am trying to combine all these queries into one if possible, hoping it will mean lesser server load time. I am not very familiar with JOINS, so ultimately this is how my code looks like with real data. And here is the result, also with real data. Is there a need to optimize/join these queries in order to decrease server load?

I would suggest to combine just last 3 queries, keep first 2 as is:
SELECT
l.`loadNumber`, l.`cfnNumber` ,
f.`value`, f.`date`,
s.`address`
FROM `loads` l
LEFT JOIN `finances` f
ON f.`load`= l.loadNumber
LEFT JOIN `stops` s
ON s.`load`= l.loadNumber
WHERE `truck`='".$var2."'

Do a subquery. Be something like this:
SELECT `item1_t1`, `item2_t1` FROM `table1` WHERE `item2_t1` in (SELECT `item1_t2` FROM `table2` WHERE `item2_t2`='".$var."');

Related

Returning results from multiple rows into separate variables with one query

Question: What is the quickest way to assign values from multiple rows of a single column into separate variables?
Using MySQL 5.6, I have a table that stores data in regular time intervals. In the insert trigger, I am attempting to detect when, among other similar things, a "peak" in the values has occurred, defined as two consecutive increasing values to a highest value, followed by two consecutive decreasing values.
Because there are several similar calculations to perform on the same data, I am first retrieving the values from a column for the last five rows into variables. I have the ID numbers of the rows.
One way to do this would be individual SELECT queries for each ID. However, I would like to consolidate them into a single query for speed, since the data will be entered into the database in blocks of 40k rows at a time.
Individual Selects:
SET currentValue = (SELECT `value` FROM `table` WHERE `tableid`=currentID);
SET prev1Value = (SELECT `value` FROM `table` WHERE `tableid`=prev1ID);
SET prev2Value = (SELECT `value` FROM `table` WHERE `tableid`=prev2ID);
SET prev3Value = (SELECT `value` FROM `table` WHERE `tableid`=prev3ID);
SET prev4Value = (SELECT `value` FROM `table` WHERE `tableid`=prev4ID);
I know another way to do this would be using joins on the same table. However, this seems like this could be a slow way to go about it. Is there a faster way to do this without using JOINs? Thanks.
Multiple JOINs:
SELECT a0.`value`, a1.`value`, a2.`value`, a3.`value`, a4.`value`
INTO currentValue, prev1Value, prev2Value, prev3Value, prev4Value
FROM (SELECT `value` FROM `table` WHERE `tableid`=currentID) AS a0
INNER JOIN (SELECT `value` FROM `table` WHERE `tableid`=prev1ID) AS a1
INNER JOIN (SELECT `value` FROM `table` WHERE `tableid`=prev2ID) AS a2
INNER JOIN (SELECT `value` FROM `table` WHERE `tableid`=prev3ID) AS a3
INNER JOIN (SELECT `value` FROM `table` WHERE `tableid`=prev4ID) AS a4
Another thing I thought of is something like:
SELECT IF(`tableid`=currentID, `value`, NULL)
, IF(`tableid`=prev1ID, `value`, NULL)
, IF(`tableid`=prev2ID, `value`, NULL)
, IF(`tableid`=prev3ID, `value`, NULL)
, IF(`tableid`=prev4ID, `value`, NULL)
INTO currentValue, prev1Value, prev2Value, prev3Value, prev4Value
FROM `table`
WHERE `tableid` IN (currentID, prev1ID, prev2ID, prev3ID, prev4ID);
But I haven't tested it yet.
For now I am going to go with the JOINs until everything is in place, and I can test the IF statement model. However, if someone knows that isn't going to work or has another method that would work better, I would appreciate it. Also, would putting this into a VIEW help with the speed of the query?
Thanks.

How to optimize double select query

SELECT `id`, `field2`, `field3`, `field4` as Title FROM `articles`
WHERE `category_id` = 'X'
AND `id` NOT IN
(SELECT `articleid` FROM `article-seen` WHERE `userid` = 'Y')
How can I optimize this?
I think double select is bad, but im new to mysql
Try using JOIN that will get you the same result but makes the query looks simpler
The optimization depends (I think) on the version of MySQL you are using.
This is how you write it as a join:
SELECT `id`, `field2`, `field3`, `field4` as Title
FROM `articles` a left outer join
`articles_seen` arts
on a.id = arts.articleid and arts.userid = 'Y'
where a.`category_id` = 'X' and
arts.id is null;
This query, at least, doesn't materialize the subquery, which (I think) your originally query would.
To makes this faster, you want to add indexes. The ones that come to mind are: articles(category_id, id) and articles_seen(userid, articleid). You could also add the fields in the select to the first index, so the entire query can be satisfied by looking at the index, rather than returning to the main table.

MYSQL query reducing the inner query in conditions

I am running into a small problem,
This is a demo query
select
A.order_id,
if(
A.production_date != '0000-00-00',
A.production_date,
if(
SOME INNER QUERY != '0000-00-00',
SOME INNER QUERY ,
SOME OTHER INNER QUERY
)
) as production_start_date
from
orders A
So basically, suppose the SOME INNER QUERY is taking 10 seconds to do its calculations, fetching data from 8 different tables, checking past history for same order type etc. and if its result is a date, I fetch that date in first condition. But now it will take 20 seconds as 10 seconds for calculation for if condition, and 10 seconds to re-execute to return the result.
Is there any way I can reduce this?
if any one is interested in looking at actual query http://pastebin.com/zqzbpEei
Assuming your query looks like this (sorry, I gave up trying to locate the actual query):
IF(
(SELECT aField FROM aTable WHERE bigCondition) != '0000-00-00',
SELECT aField FROM aTable WHERE bigCondition,
SELECT anotherField FROM anotherTable
)
You can rewrite it as follows:
SELECT IF (
someField != '0000-00-00',
someField,
SELECT anotherField FROM anotherTable
)
FROM aTable WHERE bigCondition
This way you compute bigCondition only once.
This query is quite ugly indeed.
Your major problem seems to be the misuse (and abuse, big time) of the IF() construct. It should be reserved to simple conditions and operations. The same applies to logical operators. Do not operate on entire queries. For instance, I see this one bit appears a few times in your query:
IF(
(SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id) IS NULL
OR (SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id) = '',
'6', -- by the way, why is this a string?! This is an integer, isn't it?
(SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id)
)
This is Bad. The condition should be moved into the SELECT directly. Rewrite it as below:
SELECT
IF (v1.weekends IS NULL OR v1.weekends = '', 6, v1.weekends)
FROM vendor v1 WHERE v1.vendor_id = A.vendor_id
That's two SELECT saved. Do this for every IF() that contains a query, and I am ready to bet you are going to speed up your query by several orders of magnitude.
There is a lot more to say about your current code. Unfortunately, you will probably need to refactor some parts of your ORM. Add new, more specialised methods to some classes, and make them use new queries that you crafted manually. Then refactor your current operation so that it uses these new methods.

Why is this SQL query with subquery very slow?

I have this query:
select *
from transaction_batch
where id IN
(
select MAX(id) as id
from transaction_batch
where status_id IN (1,2)
group by status_id
);
The inner query runs very fast (less than 0.1 seconds) to get two ID's, one for status 1, one for status 2, then it selects based on primary key so it is indexed. The explain query says that it's searching 135k rows using where only, and I cannot for the life of me figure out why this is so slow.
The inner query is run seperatly for every row of your table over and over again.
As there is no reference to the outer query in the inner query, I suggest you split those two queries and just insert the results of the inner query in the WHERE clause.
select b.*
from transaction_batch b
inner join (
select max(id) as id
from transaction_batch
where status_id in (1, 2)
group by status_id
) bm on b.id = bm.id
my first post here.. sorry about the lack of formatting
I had a performance problem shown below:
90sec: WHERE [Column] LIKE (Select [Value] From [Table]) //Dynamic, slow
1sec: WHERE [Column] LIKE ('A','B','C') //Hardcoded, fast
1sec: WHERE #CSV like CONCAT('%',[Column],'%') //Solution, below
I had tried joining rather than subquerying.
I had also tried a hardcoded CTE.
I had lastly tried a temp table.
None of these standard options worked, and I was not willing to dosp_execute option.
The only solution that worked as:
DECLARE #CSV nvarchar(max) = Select STRING_AGG([Value],',') From [Table];
// This yields #CSV = 'A,B,C'
...
WHERE #CSV LIKE CONCAT('%',[Column],'%')

Strange Mysql Query Performance on View

I have a view : vcompanyendofday
The following query executes in just 0.7 secs
Select * from vcompanyendofday
But a simple where condition to this query takes around 200.0 secs
select * from vcompanyendofday where companyid <= 51;
This is the view definition:
CREATE VIEW `vcompanyendofday` AS
select `c`.`companyid` AS `companyid`,
`c`.`scripcode` AS `scripcode`,
`e`.`eoddate` AS `eoddate`,
`e`.`prevclose` AS `prevclose`,
`e`.`delqty` AS `delqty`
from (
`company` `c`
left join
`endofday` `e`
on ((`c`.`companyid` = `e`.`companyid`)))
where (`e`.`eoddate` =
(
select max(`e2`.`eoddate`) AS `max(eoddate)`
from `endofday` `e2`
where (`e2`.`companyid` = `c`.`companyid`)
)
);
Seems you don't have an index on endofday.companyid
When you add the condition, company becomes leading in the join, and kills all performance.
Create an index on endofday.companyid:
CREATE INDEX ix_endofday_companyid ON endofday(companyid)
By the way, if you want all companies to be returned, you need to put the subquery into the ON clause of the OUTER JOIN, or your missing endofday's will be filtered out:
CREATE VIEW `vcompanyendofday` AS
select `c`.`companyid` AS `companyid`,
`c`.`scripcode` AS `scripcode`,
`e`.`eoddate` AS `eoddate`,
`e`.`prevclose` AS `prevclose`,
`e`.`delqty` AS `delqty`
from (
`company` `c`
left join
`endofday` `e`
on `c`.`companyid` = `e`.`companyid`
AND `e`.`eoddate` =
(
select max(`e2`.`eoddate`) AS `max(eoddate)`
from `endofday` `e2`
where (`e2`.`companyid` = `c`.`companyid`)
)
Have you tried the select used to create the view by itself with the WHERE clause to see what happens?
If the problem happens with that, run EXPLAIN on that query to see what's happening.
At a guess, there's no index on companyid in one of the tables, most likely endofday.