Query performance with OR - mysql

Maybe this is a basic question, but haven't been able to answer it, and would appreciate your help :)
I have the following table in MySQL:
create table anotation
(
chromosome enum
(
'Chr1',
'Chr2',
'Chr3',
'Chr4',
'Chr5',
'ChrC',
'ChrM'
),
version varchar(10),
type enum
(
'CDS',
'chromosome',
'exon',
'five_prime_UTR',
'gene',
'mRNA',
'mRNA_TE_gene',
'miRNA',
'ncRNA',
'protein',
'pseudogene',
'pseudogenic_exon',
'pseudogenic_transcript',
'rRNA',
'snRNA',
'snoRNA',
'tRNA',
'three_prime_UTR',
'transposable_element_gene'
),
strand enum
(
'+',
'-'
),
phase tinyint,
atrributes text
);`
And it has around 600,000 values, and I'm doing the following query:
select distinct
anot_1.chromosome,
anot_1.start,
anot_1.end,
anot_1.atrributes
from
anotation anot_1,
anotation anot_2
where
anot_1.type='CDS'
and
anot_2.type='protein'
and
anot_1.chromosome!='ChrM'
and
anot_1.chromosome!='ChrC'
and
anot_1.chromosome=anot_2.chromosome
and
(
(
anot_2.start=anot_1.start
and
anot_1.end!=anot_2.end
and
anot_2.strand='+'
)
or
(
anot_2.start!=anot_1.start
and
anot_1.end=anot_2.end
and
anot_2.strand='-'
)
);
And in it takes a long while to finish, acutally, but when I do the query (same one, but I drop the one of the conditions from the OR ) it runs almost instantely:
select distinct
anot_1.chromosome,
anot_1.start,
anot_1.end,
anot_1.atrributes
from
anotation anot_1,
anotation anot_2
where
anot_1.type='CDS'
and
anot_2.type='protein'
and
anot_1.chromosome!='ChrM'
and
anot_1.chromosome!='ChrC'
and
anot_1.chromosome=anot_2.chromosome
and
anot_2.start=anot_1.start
and
anot_1.end!=anot_2.end
and
anot_2.strand='+';`
Anyone has any idea of whats happening and if so, how can I solve it?
Thank you!!!

This isn't a solution (and I agree with comments above about indexes), but I have changed your SQL around to use a pair of left outer joins rather than your current SQL which has an OR in the JOIN.
While I don't expect this to be much different in performance it might help you and others see what the query is doing:-
SELECT distinct anot_1.chromosome, anot_1.start, anot_1.end, anot_1.atrributes
FROM anotation anot_1,
LEFT OUTER JOIN anotation anot_2 ON anot_1.chromosome = anot_2.chromosome AND anot_1.start = anot_2.start AND anot_1.end != anot_2.end AND anot_2.strAND = '+' AND anot_2.type='protein'
LEFT OUTER JOIN anotation anot_3 ON anot_1.chromosome = anot_3.chromosome AND anot_1.end = anot_3.end AND anot_1.start != anot_3.start AND anot_3.strAND = '+' AND anot_3.type='protein'
WHERE anot_1.type = 'CDS'
AND anot_1.chromosome != 'ChrM'
AND anot_1.chromosome != 'ChrC'
AND (anot_2.chromosome IS NOT NULL
OR anot_3.chromosome IS NOT NULL)

I'd start by sanitising your query in general, breaking them apart and doing a union
select
CDS.chromosome,
CDS.start,
CDS.end,
CDS.atrributes
from
(
select
a.chromosome,
a.start,
a.end,
a.attribures,
from
anotation a,
where
a.type='CDS'
and
not a.chromosome IN ('ChrM', 'ChrC')
) CDS
join
(
select
a.strand,
from
anotation a,
where
a.type='protien'
) Protien
on
CDS.chromosome = Protien.chromosome
and
CDS.start = Protien.start
and
CDS.end != Protien.end
where
Protien.strand = '+'
union
select
CDS.chromosome,
CDS.start,
CDS.end,
CDS.atrributes
from
(
select
a.chromosome,
a.start,
a.end,
a.attribures,
from
anotation a,
where
a.type='CDS'
and
not a.chromosome IN ('ChrM', 'ChrC')
) CDS
join
(
select
a.strand,
from
anotation a,
where
a.type='protien'
) Protien
on
CDS.chromosome = Protien.chromosome
and
CDS.start != Protien.start
and
CDS.end = Protien.end
where
Protien.strand = '-'

Related

Query blocking entirely MySQL server

I try to a run a specific query. However, when I execute it, the MySQL server doesn't respond anymore.
There is approximately 30000 rows in the table base_contrats_actifs but I don't know if this is a problem.
Here is the query :
UPDATE
base_contrats_actifs a
SET
a.code_indice = (
SELECT
MAX(g.code_indice)
FROM
base_gid g
WHERE
a.num_version = g.num_version_contrat
),
a.flag_bailleur_locataire = (
SELECT
MAX(g.flag_bailleur_locataire)
FROM
base_gid g
WHERE
a.num_version = g.num_version_contrat
),
a.compte_client = (
SELECT
MAX(g.compte_client)
FROM
base_gid g
WHERE
a.num_version = g.num_version_contrat
)
Can you see if there is an error ? If not, is there any way to debug the query ?
I don't know exactly why your update is non performant, but given the number of correlated subqueries you have, I'm not surprised. Try rewriting it as an update join:
UPDATE base_contrats_actifs a
INNER JOIN
(
SELECT
num_version_contrat,
MAX(code_indice) AS max_code_indice,
MAX(flag_bailleur_locataire) AS max_flag_bailleur_locataire,
MAX(compte_client) AS max_compte_client
FROM base_gid
GROUP BY num_version_contrat
) g
ON a.num_version = g.num_version_contrat
SET
a.code_indice = g.max_code_indice,
a.flag_bailleur_locataire = g.max_flag_bailleur_locataire,
a.compte_client = g.max_compte_client;

MySQL best select multi condition query

I have a MySQL query:
SELECT * FROM product_variants WHERE (bottom_type = '$bottom_type1' OR bottom_type = '$bottom_type2' ) AND (bottom_size = '$bottom_size ' ) AND (product_id != '$product_id1 ' OR product_id != '$product_id2' OR product_id != '$product_id3')
It is not working as it should, its not giving me the results needed.
What is the best way to build it?
Thanks
This is just my guess at what you're after. Example table structure, with data and expected results would help answer your question.
SELECT *
FROM product_variants
WHERE bottom_type IN ('$bottom_type1', '$bottom_type2')
AND bottom_size = '$bottom_size'
AND product_id NOT IN ('$product_id1 ', '$product_id2', '$product_id3')

How to query a SQL statement which depends on other values of same table?

I have a table with 3 columns( name, objectroot_dn, distinguishedname). Here distinguishedname is like a parent to objectroot_dn. I have to find whether for each objectroot_dn is there a child exists or not?
I can do this using the query below. It will return True if there is a child, False if there is not. But my problem is when the total dataset gets increased it takes lots of time.
For example, If the total number of row is 50,000 then it takes 10 mins for this query to complete.
Since I'm using a framework for different database, I can't index the columns.
SELECT
name,
objectroot_dn,
distinguishedname,
CASE
WHEN (SELECT count(*)
FROM (SELECT name
FROM elaoucontainergeneraldetails
WHERE objectroot_dn = dn.distinguishedname
LIMIT 1) AS tabel1) > 0
THEN 'True'
ELSE 'False'
END
FROM elaoucontainergeneraldetails AS dn
WHERE objectroot_dn = 'SOME_VALUE';
Please let me know how can I increase the speed of this query.
Thanks in advance. Appreciate all help.
You can have the same solution using left join or exists:
SELECT
dn.name,
dn.objectroot_dn,
dn.distinguishedname,
CASE
WHEN dn_in.objectroot_dn is not null
THEN 'True'
ELSE 'False'
END
FROM elaoucontainergeneraldetails AS dn
LEFT JOIN elaoucontainergeneraldetails dn_in on dn_in.objectroot_dn = dn.distinguishedname
WHERE objectroot_dn = 'SOME_VALUE';
EXISTS(subquery) yields a boolean value:
SELECT dn.name
, dn.objectroot_dn
, dn.distinguishedname
, EXISTS (SELECT *
FROM elaoucontainergeneraldetails nx
WHERE nx.objectroot_dn = dn.distinguishedname
) AS truth_value
FROM elaoucontainergeneraldetails AS dn
WHERE dn.objectroot_dn = 'SOME_VALUE'
;

Convert time "28:45" to "4:45" MySQL

I'm looking for a way to order my results based on the actual time. In my table yo can see values like:
1,23:45
2,9:45
3,27:43
When I do a query I would like to know how to order them based on their actual 24 hour time.
Ex:
3,3:43
2,9:45
1,23:45
Notice how it changes 27:43 to 3:43, and creates the order.
Where I am using it, in this query:
SELECT *,COALESCE(ADDTIME(s.`departure_time`,SEC_TO_TIME(rt.delay)),s.`departure_time`) as `rt_time` FROM `stop_times` s INNER JOIN `trips` t ON s.`trip_id` = t.`trip_id` INNER JOIN `stops` st ON st.`stop_id` = s.`stop_id` INNER JOIN `routes` r ON r.`route_id` = t.`route_id` LEFT JOIN `rt_trips` rt ON t.`trip_id` = rt.`trip_id` where (s.`stop_id` = 'CB900') and ( ( s.`departure_time` >= '00:50' and s.`departure_time` <= '05:50') OR ( s.`departure_time` >= '24:50' and s.`departure_time` <= '29:50') ) and (s.`pickup_type` = '0') and (t.`service_id` IN ('removed to make it easier')) HAVING (`rt_time` BETWEEN '01:50' and '05:50' ) ) OR ( `rt_time` BETWEEN '25:50' and '29:50' ) ORDER BY `order` ASC
Explanation:
Information is a transit schedule, that may go forward onto the next day which may be a saturday. So, times may become 25:50, where that means 1:50 the next day.
Thanks
Cyrus
Hmmm, if you just want to get a value between 0 and 24 hours, then I would do:
select concat(mod(substring_index(time_column, ':', 1) + 0, 24), ':',
substring_index(time_column, ':', -1)
)
Try this function on the time_column
concat(mod(substr(time_column,1,INSTR(time_column, ':')-1),24)
,substr(time_column,INSTR(time_column, ':'),3)
)
You might need to cast date to string to integer, do the maths, and again cast it to time. But the fiddle version seems to work properly on varchar to integer conversion. Check this
http://sqlfiddle.com/#!9/ff60f9/1

sql insert multiple rows with inner selects

I need to insert multiple rows , but some of the data have to come from inner select
i having problem to construct the right sql statement for example i have :
insert into game_friends(
game_users_id,
game_users_id_name,
created_to_app_users_id,
created_to_app_users_id_name
) VALUES ......
now the problematic part is that the created_to_app_users_id_name and game_users_id_name i can get only by using select like this:
SELECT app_users_game_users_id_name
FROM `app_users` WHERE app_users_game_users_id = $game_users_id
and
SELECT app_users_created_to_app_users_id_name
FROM `app_users`
WHERE app_users_created_to_app_users_id = $created_to_app_users_id
how can i combine it to one sql statement using mysql
UPDATE:
Thanks to all for answering , but i guess didnt explain my problem right ...
i need to insert multiple rows that means i will have like 5-7 game_users_id coming
and it needs in the end look like ( with out the select here .. )
insert into game_friends(
game_users_id,
game_users_id_name,
created_to_app_users_id,
created_to_app_users_id_name
)
VALUES
($game_users_id, app_users_created_to_app_users_id_name, $created_to_app_users_id,app_users_created_to_app_users_id_name ),
($game_users_id, app_users_created_to_app_users_id_name, $created_to_app_users_id,app_users_created_to_app_users_id_name ),
($game_users_id, app_users_created_to_app_users_id_name, $created_to_app_users_id,app_users_created_to_app_users_id_name ),
($game_users_id, app_users_created_to_app_users_id_name, $created_to_app_users_id,app_users_created_to_app_users_id_name );
where each Values entry need to be composed from select.
try this code for PHP:
$query = "insert into game_friends(
game_users_id,
game_users_id_name,
created_to_app_users_id,
created_to_app_users_id_name
) SELECT
app_users_game_users_id,
app_users_game_users_id_name,
app_users_created_to_app_users_id,
app_users_created_to_app_users_id_name
FROM `app_users` WHERE
app_users_game_users_id = $game_users_id
AND
app_users_created_to_app_users_id = $created_to_app_users_id";
this is UNTESTED.
insert into game_friends
(
game_users_id,
game_users_id_name,
created_to_app_users_id,
created_to_app_users_id_name
)
VALUES
SELECT game_users_id,
created_to_app_users_id,
FinalTable.game_users_id_name,
FinalTable.created_to_app_users_id_name
FROM
((SELECT app_users_game_users_id as game_users_id,
app_users_game_users_id_name as game_users_id_name
FROM app_users
WHERE app_users_game_users_id = game_users_id) as iGameID
INNER JOIN
(SELECT app_users_created_to_app_users_id as created_to_app_users_id,
app_users_created_to_app_users_id_name as created_to_app_users_id_name
FROM app_users
WHERE app_users_created_to_app_users_id = created_to_app_users_id) as iCreatedID
ON iGameID.game_users_id = iCreatedID.created_to_app_users_id) as FinalTable
Simple SELECT over two tables without any JOINs should do the trick (assuming each select statement returns only one row):
INSERT INTO game_friends (
game_users_id,
game_users_id_name,
created_to_app_users_id,
created_to_app_users_id_name
)
SELECT u_game.app_users_game_users_id,
u_game.app_users_game_users_id_name,
u_created.app_users_created_to_app_users_id,
u_created.app_users_created_to_app_users_id_name
FROM `app_users` u_game,
`app_users` u_created
WHERE u_game.app_users_game_users_id = $game_users_id
AND u_created.app_users_created_to_app_users_id = $created_to_app_users_id
Another note: I am guessing that you app_users table does really have a column app_users_game_users_id or app_users_created_to_app_users_id. In which case you should replace those in the SQL with the real column name, which again I guess is either user_id, app_user_id or id. It is just that your model looks very strange otherwise assuming that both of the above mentioned columns are supposed to be unique in the table.