How to speed up MySQL query? Loading data from 3 tables - mysql

I have 3 tables.
First: "atributy"
Second: "atributy_value"
Third: "produkty"
I have this query first:
SELECT a.*, p.ATTRIBUTE_CODE, p.ATTRIBUTE_VALUE, p.KATEGORIA
FROM atributy a JOIN produkty p ON p.ATTRIBUTE_CODE
LIKE CONCAT('%', a.code, '%')
AND
KATEGORIA IN ('$kategoria_sql')
GROUP BY a.value
And my second query is this:
SELECT * FROM atributy_value
INNER JOIN produkty
ON produkty.ATTRIBUTE_VALUE LIKE CONCAT('%', atributy_value.ValueCode, '%')
AND AttributeCode = '$atribut_kod'
AND KATEGORIA IN ('$kategoria_sql')
GROUP BY atributy_value.Value
Help me please make from this 2 query's 1 one better.
Reason: too long loading my web e-shop.
EDIT:
$query = mysql_query("
SELECT a.*, p.ATTRIBUTE_CODE, p.ATTRIBUTE_VALUE, p.KATEGORIA
FROM atributy a JOIN produkty p ON p.ATTRIBUTE_CODE LIKE CONCAT('%', a.code, '%')
AND KATEGORIA IN ('$kategoria_sql')
GROUP BY a.value ");
while($result = mysql_fetch_object($query)){
$atribut_kod = $result->code;
$atribut_value = $result->value;
$nazov_produktu = $result->NAZOV;
$value1 = $result->ATTRIBUTE_VALUE;
$value1 = explode(" ", $value1);
$value1_count = count($value1);
echo "<div class=\"parametre_panel\">
<h3>".$atribut_value."</h3>
";
$url_kody .= "$atribut_kod,";
$hodnoty_qry = mysql_query("
SELECT * FROM atributy_value
INNER JOIN produkty ON produkty.ATTRIBUTE_VALUE LIKE CONCAT('%', atributy_value.ValueCode, '%')
AND AttributeCode = '$atribut_kod'
AND KATEGORIA IN ('$kategoria_sql')
GROUP BY atributy_value.Value ");
while($hodnoty_res = mysql_fetch_object($hodnoty_qry)){
$cislo_hodnoty = $hodnoty_res->ValueCode;
echo "<input type=\"checkbox\" class=\"ZobrazParametrickeVyhladavanie\" name=\"value[]\" id=\"$cislo_hodnoty\" value=\"".$atribut_kod."-".$cislo_hodnoty."\"><label for=\"$cislo_hodnoty\">".$hodnoty_res->Value."</label>
";
$url_hodnoty .= "$cislo_hodnoty,";
} //second query while()
echo "</div>";
} //first query while()
EDIT 2:
My table structure
produkty: http://i.imgur.com/J4Kz2CE.png
atributy_value: http://i.imgur.com/nX1uRph.png
atributy: http://i.imgur.com/mlCa3It.png
Indexes:
atributy: http://i.imgur.com/ppMEEOe.png
atributy_value: http://i.imgur.com/RHAeSiu.png
produkty: http://i.imgur.com/IUrgy9l.png

You can try Below Query:
SELECT a.*,
p.ATTRIBUTE_CODE,
p.ATTRIBUTE_VALUE,
p.KATEGORIA
FROM atributy a
JOIN (SELECT *
FROM atributy_value
INNER JOIN produkty
ON produkty.ATTRIBUTE_VALUE LIKE CONCAT('%', atributy_value.ValueCode, '%')
AND AttributeCode = '$atribut_kod'
AND KATEGORIA IN ('$kategoria_sql')
GROUP BY atributy_value.Value) p
ON p.ATTRIBUTE_CODE LIKE CONCAT('%', a.code, '%')
AND KATEGORIA IN ('$kategoria_sql')
GROUP BY a.value
In Inner Query Select Only Required Columns
Hope this works.

1) Run an EXPLAIN on your queries and add indexes where necessary. IMHO, these queries are not meant to run on production. However, I have made a suggestion below.
2) Let MySQL handle the query execution plan for you. Instead of mentioning a JOIN. Try this
$query = mysql_query("
SELECT a.*, p.ATTRIBUTE_CODE, p.ATTRIBUTE_VALUE, p.KATEGORIA
FROM atributy a,produkty p
WHERE p.ATTRIBUTE_CODE LIKE CONCAT('%', a.code, '%')
AND KATEGORIA IN ('$kategoria_sql')
GROUP BY a.value ");
2) Also change the inner query to the following:
SELECT atributy_value.* FROM atributy_value AS atributy_value, produkty AS produkty
WHERE
produkty.ATTRIBUTE_VALUE LIKE CONCAT('%', atributy_value.ValueCode, '%')
AND atributy_value.AttributeCode = '$atribut_kod'
AND produkty.KATEGORIA IN ('$kategoria_sql')
GROUP BY atributy_value.Value ")
I need more details on the table structures though
3) Run an EXPLAIN on the above query. If you have any missing indexes, please add them

Two things are slow here.
First - unnecessary outer / inner loop. It should be possible to do this in a single SQL query, which will be a huge time saving.
Without seeing the definitions of your tables, this is the best I can suggest :
SELECT a.*, p.*, av.*
FROM produkty p
JOIN atributy a ON p.ATTRIBUTE_CODE LIKE CONCAT('%', a.code, '%')
JOIN atributy_value av ON p.ATTRIBUTE_VALUE LIKE CONCAT('%', av.ValueCode, '%')
WHERE
KATEGORIA IN ('$kategoria_sql')
At least it's a starting point to test from.
Second - Joining between the two tables using LIKE '%value%'. Is there not an integer ID that links these two tables together? Or at least, should the text be an exact match and you can remove the '%'s?
EDIT (after adding table structure) :
You have two joins, the first from a nice indexed integer atributy_value.ValueCode to a non-indexed text field produkty.ATTRIBUTE_CODE, the second from a non indexed text field atributy.code to another non-indexed text field produkty.ATTRIBUTE_CODE.
It's not a good table structure, it would be easier and faster if every table had a unique integer ID to join on. But you might not have time to change this.
Can you just remove the %'s in your original queries and insist on an exact match between the columns?
To keep it simple, you could just replace :
LIKE CONCAT('%', a.code, '%')
replace with
= a.code
and
LIKE CONCAT('%', atributy_value.ValueCode, '%')
replace with
= CONVERT( varchar(500), atributy_value.ValueCode)
This will make it faster. If it's still not enough you could add indexes on Produkty.ATTRIBUTE_CODE and Produkty.ATTRIBUTE_VALUE and atributy.code.

Related

Use Sql Join two times on a single table

This is my query in 3 Nested form. What i want is to re-write this query using JOINS but the problem is same table is repeating two times as you can see.
$query = "
SELECT
*
FROM userinfo
WHERE id IN (
SELECT DISTINCT
iduser
FROM u_n_relation
WHERE idnetwork IN (
SELECT
idnetwork
FROM u_n_relation
WHERE iduser = '$userid'
)
)
AND virtual_name LIKE CONCAT('%', ?, '%')
ORDER BY id LIMIT 5
"
What i tried was this :
$query = "
SELECT
userinfo.*
FROM userinfo
INNER JOIN u_n_relation ON (u_n_relation.iduser = userinfo.id)
WHERE
(userinfo.virtual_name LIKE CONCAT('%', ?, '%')
AND u_n_relation.iduser = '$iduser')
ORDER BY userinfo.id LIMIT 5
"
But still not getting the correct result.
Can anyone please shed some light on how to do this?
Basically what the query says is :
Fetch the details of the users who have joined the networks you have joined.
select distinct is not needed when you use in. However, it may be needed when you use join. Otherwise you can turn the ins into inner joins:
SELECT ui.*
FROM userinfo ui JOIN
(SELECT DISTINCT unr.iduser
FROM u_n_relation unr JOIN
u_n_relation unr2
ON unr.idnetwork = unr2.idnetwork and
unr2.iduser = '$userid'
WHERE unr.virtual_name LIKE CONCAT('%', ?, '%')
) unr
ON ui.id = unr.iduser
ORDER BY id
LIMIT 5;
Firstly, Mark L. is correct in that aliases are the key to JOINing the same table multiple times in a query.
Secondly, holy crap formatting. Formatting is especially important when posting your query to ask a question about it. Your formatting caused Gordon L. to mis-read which table the "virtual_name" field was in.
Initially your first query didn't make sense to me but jackkorbins comment got me to view it again and I get it this time - here it is formatted more read-ably:
SELECT *
FROM
userinfo
WHERE
id IN (-- This sub-query returns *any* iduser that is a member
-- of those same networks
SELECT DISTINCT
iduser
FROM
u_n_relation
WHERE
idnetwork IN (-- This sub-query returns the multiple networks
-- that have $userid as a member
SELECT
idnetwork
FROM
u_n_relation
WHERE
iduser = '$userid'))
AND virtual_name LIKE CONCAT('%', ?, '%')
ORDER BY
id
LIMIT 5
So another way to make a JOIN version of that query would look like:
SELECT DISTINCT
ui.*
FROM
u_n_relation unr
INNER JOIN u_n_relation net
ON (net.idnetwork=unr.idnetwork)
INNER JOIN userinfo ui
on ( ui.id = net.iduser )
WHERE
unr.iduser = '$iduser'
and ui.virtual_name LIKE CONCAT('%', ?, '%')
ORDER BY
ui.id
LIMIT 5
Sorry for my earlier confusion. :-)

Working LIKE statement with % on column names but rows repeated

I have my SELECT query used with LIKE statement working but am shocked; that my rows fetched are repeated, and i don't know why?
SELECT *
FROM questions, counts
WHERE counts.test_coursecode LIKE '%' || questions.coursecode || '%'
You must include the inner join of the two tables
SELECT *
FROM questions q inner join counts c on a q.id and c.fk
WHERE counts.test_coursecode LIKE CONCAT('%', questions.coursecode, '%')
or
SELECT *
FROM questions q , counts c
where a q.id and c.fk
and counts.test_coursecode LIKE CONCAT('%', questions.coursecode, '%')
I'm assuming you want to use
SELECT *
FROM questions, counts
WHERE counts.test_coursecode LIKE CONCAT('%', questions.coursecode, '%')
instead.
|| is not the concatenation operator but the logical OR in the sql dialect of MySQL.
Your query will match every row, because any value will match the first expression, it evaluates to
SELECT *
FROM questions, counts
WHERE counts.test_coursecode LIKE '%' -- that's true, if test_course_code is not null
OR questions.coursecode
OR '%'

Match description with giving code word

Need help with this query, cannot get it work right
SELECT a.code, a.description, a.adjustment FROM activity AS a
WHERE a.pid = $customer_id AND a.consult = $consultation_id AND a.code LIKE $code
$code equals can be a something like this "12043 OFFICE CONSULT' (of course different numbers for different descriptions) OR 'DE-POSIT' OR 'UNKNOWN'
the problem is that DBs store this like "12043 OFF" OR UNKNOWN. My query only matches the unknown but not the ones with the number. It can match a number if I do
a.code REGEXP '^[0-9]+' but matches any number not exact match.
If there are multiple lines with different numbers it puts the first match on all the lines
try using LIKE CONCAT('%', $code ,'%')
SELECT a.code, a.description, a.adjustment FROM activity AS a
WHERE a.pid = $customer_id AND a.consult = $consultation_id AND a.code LIKE CONCAT('%', $code ,'%')
Can you try , LIKE '%$code%' it fetches the record it contains the code value.
"SELECT a.code, a.description, a.adjustment FROM activity AS a
WHERE a.pid = $customer_id AND a.consult = $consultation_id AND a.code LIKE '%$code%'";
Ref: http://www.tutorialspoint.com/mysql/mysql-like-clause.htm

Optimize SQL statement with multiple CONCAT clauses?

SELECT
*
FROM
pages
INNER JOIN cms_collection ON cms_collection.collection_id LIKE
(
CONCAT('%', pages.page_id, '/heading%') OR
CONCAT('%', pages.page_id, '/content%')
)
WHERE
site_id = 51
LIMIT 10
The stacked CONCATs are causing the query to be super slow, is there anyway to optimize this? And actually it seems like this statement isn't working as expected.. I want to do a LIKE based on if the collection_id is '%pages.page_id/heading%' OR '%pages.page_id/content%'.
This statement works fine if just the first CONCAT exists.
OR is a logical operator. It does not define alternatives for LIKE. You need to split that out into two LIKE clauses.
SELECT * FROM pages
INNER JOIN cms_collection ON
(cms_collection.collection_id LIKE CONCAT('%', pages.page_id, '/heading%')) OR
(cms_collection.collection_id LIKE CONCAT('%', pages.page_id, '/content%'))
WHERE site_id = 51 LIMIT 10
If that is still slow, add your table structure and the output of an EXPLAIN to your question.
SELECT * FROM pages
INNER JOIN cms_collection ON
(cms_collection.collection_id LIKE CONCAT('%', pages.page_id, '/heading%'))
WHERE site_id = 51
UNION ALL
SELECT * FROM pages
INNER JOIN cms_collection ON
(cms_collection.collection_id LIKE CONCAT('%', pages.page_id, '/content%'))
WHERE site_id = 51
LIMIT 10
;
Using UNION ALL instead of OR improves performance

Join two strings from db together

I have produced the following query.
SELECT t.id AS playerid,
dp.first_name,
dp.surname
FROM ".TBL_FOOT_CAREER_TEAMS." t
INNER JOIN ".TBL_FOOT_CAREER_DB_PLAYERS." dp
ON dp.id = t.playerid
WHERE t.careerid = '$career'
AND (dp.first_name LIKE '%{$keyword[$i]}%')
OR (dp.surname LIKE '%{$keyword[$i]}%')
OR (`dp.first_name + dp.surname` LIKE '%{$keyword[$i]}%')
There are two columns in the database. first_name and surname. As you can see, I'm trying to check if the keyword is in either of those columns. I also try and make them into one complete name and check if that's what the search term is aswell.
I'm getting an error so I can assume this isn't the way to do it!!
Can someone help :)
Thanks
SELECT t.id AS playerid,
dp.first_name,
dp.surname
FROM ".TBL_FOOT_CAREER_TEAMS." t
INNER JOIN ".TBL_FOOT_CAREER_DB_PLAYERS." dp
ON dp.id = t.playerid
WHERE (t.careerid = '$career') AND
(
(dp.first_name LIKE concat('%', $keyword[$i], '%')) OR
(dp.surname LIKE concat('%', $keyword[$i], '%')) OR
(CONCAT(dp.first_name, ' ',dp.surname) LIKE concat('%', $keyword[$i], '%'))
)
UPDATE
since you are concactenating the name, you can it like this:
SELECT t.id AS playerid,
dp.first_name,
dp.surname
FROM ".TBL_FOOT_CAREER_TEAMS." t
INNER JOIN ".TBL_FOOT_CAREER_DB_PLAYERS." dp
ON dp.id = t.playerid
WHERE (t.careerid = '$career') AND
(
CONCAT(dp.first_name, ' ',dp.surname) LIKE concat('%', $keyword[$i], '%')
)
Use CONCAT() in your query: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat
...
OR CONCAT(dp.first_name, dp.surname) LIKE '%{$keyword[$i]}%'