JOIN slow nown my Query - php

How can i update this query, to give me more speed?
Why is the query slower, when I use JOIN?
SELECT v.vare_id,
LEFT(v.varenavn, 25) as varenavn,
v.salgspris,
ve.enhed,
ve.vare_enhed_id,
vt.tilstand,
vt.vare_tilstand_id,
v.oko_vare,
v.varefoto
FROM vare v
JOIN vare_enhed_valg vev
ON vev.vare_id = v.vare_id
JOIN vare_enhed ve
ON ve.vare_enhed_id = vev.enhed_id
JOIN vare_tilstand_valg vtv
ON vtv.vare_id = v.vare_id
JOIN vare_tilstand vt
ON vt.vare_tilstand_id = vtv.tilstand_id
WHERE v.vare_type_id = 1
AND v.synlig = "ja"
ORDER BY v.varenavn ASC

For your query, you want an index on: vare(vare_type_id, v.synlig, v.varenavn). Other indexes might be appropriate. Let me assume that the join keys include the primary key of at least one of the tables.

Related

PHP and MySQL - use HAVING on count or no HAVING and array_filter?

I'd like to ask if there is a good practise about performance of following.
My SQL SELECT:
SELECT avpc.category_id, a.attribute_id, ad.name, a.type, a.sort_order, avpc.attribute_value_id, avd.value, COUNT(pav.product_id) AS product_count
FROM attribute_value_per_category avpc
JOIN category_path cp ON cp.category_id = avpc.category_id
JOIN attribute_value av ON av.attribute_value_id = avpc.attribute_value_id
JOIN attribute_value_description avd ON avd.attribute_value_id = av.attribute_value_id AND avd.language_id = 2
JOIN attribute a ON a.attribute_id = av.attribute_id
JOIN attribute_description ad ON ad.attribute_id = a.attribute_id AND ad.language_id = 2
JOIN product_attribute_value pav ON pav.attribute_value_id = av.attribute_value_id
WHERE path_id = 2
GROUP BY attribute_value_id
I need to add condition: HAVING product_count > 10. I've read, that HAVING is very slow and there is no optimisation in.
So I've got these two suggestions:
Use HAVING
Not use HAVING and filter out the condition in PHP (For example by array_filter)
Would you please to give me any advice of performance of this problem?

Join a query into another query with column computation

I have three tables named issue_details, nature_payments, and rci_records. Now I have this query which joins this three tables.
SELECT issue_details.issue_date AS Date,
issue_details.check_no AS Check_No,
payees.payee_name AS Name_payee,
nature_payments.nature_payment AS Nature_of_Payment,
issue_details.issue_amount AS Checks_issued,
issue_details.nca_balance AS Nca_balance
FROM
issue_details
INNER JOIN
nature_payments ON
issue_details.nature_id = nature_payments.nature_id
INNER JOIN
payees ON
issue_details.payee_id = payees.payee_id
ORDER BY Date Asc, Check_no ASC
On my column in Nca_balance, this is a computed differences of every issuances of check. But you may not know what really the process of how I got the difference but to make it simple, let's say that I have another query
that dynamically get also the difference of this nca_balance column. Here is the query:
SELECT r.*,
(#tot := #tot - issue_amount) as bank_balance
FROM (SELECT #tot := SUM(nca_amount) as nca_total FROM nca
WHERE account_type = 'DBP-TRUST' AND
year(issue_date) = year('2015-01-11') AND
month(issue_date) = month('2015-01-11')
)
vars CROSS JOIN issue_details r
WHERE r.account_type = 'DBP-TRUST' AND
r.issue_date = '2015-01-11'
ORDER BY r.issue_date, r.check_no
I know it you may not get my point but I just want to replace the first query of the line
issue_details.nca_balance AS Nca_balance
with my own computation on my second query.
Please help me combine those two query into a single query. Thanks

mysql Query Optimization with inner join

I have a query
$query = "SELECT DISTINCT report_date,weekreportDate FROM contract_sales a
INNER JOIN contract b ON a.contract_UUID = b.UUID
INNER JOIN geoPoint c ON b.customer_UUID = c.customerUUID
WHERE c.com_UUID = '$com' AND a.report_date >= Date('$dateafter')
AND c.city_UUID = '$cit' ORDER BY `report_date`";
What I need to do is first get rid of all the results via date filtering but as you can see I get everything and then do my date sorting in the checks..
I am inner join all of them - is there a better way to do this?
I have a report for each date - and have two years of data - I want to get only dates in 2014 so as you can see I have 700+ dates that are useless to me right away but I have to go through all of them can check the other string UUID as well... what can I do to speed up my (working - albeit slow implementation)?
Explain information as requested:
Generation Time: Feb 20, 2014 at 06:48 PM
Generated by: phpMyAdmin 3.3.10.4 / MySQL 5.1.53-log
SQL query: EXPLAIN SELECT DISTINCT report_date,weekreportDate FROM contract_sales a INNER JOIN contract b ON a.contract_UUID = '1234' INNER JOIN geoPoint c ON b.customer_UUID = '1234' WHERE c.com_UUID = '1234' AND a.report_date >= Date('2014-01-01') AND c.city_UUID = '1234' ORDER BY `report_date`;
Rows: 3
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE a ref uuid_conlcs uuid_conlcs 110 const 1 Using where; Using temporary; Using filesort
1 SIMPLE b ref uuid_cust uuid_cust 110 const 1 Using where; Using index; Distinct
1 SIMPLE c ref uuid_gargp,uuid_citgp uuid_citgp 110 const 1 Using where; Distinct
First, a rewrite of your query. I would not suggest using aliases just a, b, c, but something closer to context of table "cs" for contract_sales, "con" for contract, and "gp" for geoPoint... especially easier in larger more complex queries.
Also, ALWAYS try to qualify your query with table.column (or alias.column) as the WeekReportDate is not clear, but it appears to be associated with your contract sales table.
As for indexes in this construct, I would have an index on (report_date, weekreportDate, contract_uuid). This way, its a covering index to handle the columns being retrieved, the where clause, order by, and the join to the contract table without having to go back to the raw data pages.
The contract table, I would have an index on ( UUID, customer_UUID), also to be a covering index for the join from contract sales, and also to support the join to the geoPoint table.
Finally, your geoPoint table, an index on ( customerUUID, com_uuid, city_uuid ) to also cover the join and your filtering criteria.
SELECT DISTINCT
cs.report_date,
cs.weekreportDate
FROM
contract_sales cs
INNER JOIN contract con
ON cs.contract_UUID = con.UUID
INNER JOIN geoPoint gp
ON con.customer_UUID = gp.customerUUID
AND gp.com_UUID = '$com'
AND gp.city_UUID = '$cit'
WHERE
cs.report_date >= Date('$dateafter')
ORDER BY
cs.report_date
Now that being said, and I don't know the makeup of your tables for volume, but if you are looking for stuff for a particular COM/City, I would suspect that records qualifying that would be a much smaller set than ALL COM/City for the date range in question. So, I would reverse the query as below hoping the smaller dataset might query faster, but you would have to obviously try both out.
SELECT DISTINCT
cs.report_date,
cs.weekreportDate
FROM
geoPoint gp
INNER JOIN contract con
ON gp.customerUUID = con.customer_UUID
JOIN contract_sales cs
ON con.UUID = cs.contract_UUID
AND cs.report_date >= Date('$dateafter')
WHERE
gp.com_UUID = '$com'
AND gp.city_UUID = '$cit'
ORDER BY
cs.report_date
Actually the geoPoint index should be on your WHERE criteria first, then the customer UUID for the join to the next table (com_uuid, city_uuid, customeruuid ). The contract_sales index on ( contract_UUID, report_date ), and the contract table index on (customer_UUID, UUID ) to match the flow of joins of this query.

Better way to do this subquery

Let's say I have this query:
<?
$qi = $db->prepare('SELECT one.id, one.Value, two.Name, three.nfid, temp.Name AS Alias
FROM one
INNER JOIN two ON one.fid = two.id
LEFT OUTER JOIN three ON two.fid = three.fid
LEFT OUTER JOIN (SELECT id,Name FROM two) AS temp ON three.nfid = temp.id
WHERE one.rid = ?
ORDER BY one.id ASC');
$qi->execute( array( $id ) );
?>
Connections between the tables are:
Table one contains a number of rows with the fields one.Value, one.rid and one.fid.
fid is a connection to table two which contains the two.Name of the items (one.fid = two.id).
But sometimes the item is an alias for another item, which is why table three exists. It contains the fields three.fid and three.newfid where three.newfid = two.id (but for another item with another two.Name)
The query is supposed to fetch all rows from one with a certain one.rid and get one.Value, two.Name and if there is an three.fid for this one.fid, get two.Name for three.newfid and call it Alias.
Is there a way to improve this query or solve the problem in another way? Perhaps reshape the layout of the database? It is currently quite slow. The example here have been simplified to make it more general.
Thank you.
The subquery in parentheses forces MYSQL to ignore its indexes, which makes it take a long time. Better to directly join two as temp. As long as you always put two.[field] and temp.[field], it will tell them apart just fine.
SELECT one.id, one.Value, two.Name, three.nfid, temp.Name AS Alias
FROM one
INNER JOIN two ON one.fid = two.id
LEFT OUTER JOIN three ON two.fid = three.fid
LEFT OUTER JOIN two AS temp ON three.nfid = temp.id
WHERE one.rid = ?
ORDER BY one.id ASC

Query with join query, need assistance

I have three tables.
I combine the company and component tables with this code
$questions_query = "SELECT company_mast.id, component_mast.component_id
FROM company_mast
LEFT JOIN component_mast
ON company_mast.id = component_mast.company_id
WHERE component_mast.component_name = '".$component_name."'
AND company_mast.company_name = '".$company_name."'";
The result is as desired, If I put company_name as Bells and component_name as Assets I get and id of 3 for Bells and an id of 9 for Assets. Now if you look at the customfields table I need to pull all the questions with the a specific company_id and component_id.
Example: If the user enters Bells and Assets they need to receive all questions with the company_id of 3 and the component_id of 9.
So this is my query
SELECT *
FROM customfield_mast
LEFT JOIN ( SELECT company_mast.id, component_mast.component_id
FROM company_mast
LEFT JOIN component_mast
ON company_mast.id = component_mast.company_id
WHERE component_mast.component_name = 'Assets'
AND company_mast.company_name = 'Bells')
att
ON customfield_mast.company_id = customfield_mast.component_id
This however returns all questions in my db, which is not what I want. I'm positive my last "ON" statement is the problem, however I don't know what the correct statement would be. I have not started with SQL injection protection, this is grass roots to get my queries to work. Thanks for the help
What's wrong with another join?
SELECT company_mast.id, component_mast.component_id, CFM.DisplayName
FROM company_mast
LEFT JOIN component_mast
ON company_mast.id = component_mast.company_id
LEFT JOIN CustomField_mast CFM
ON CFM.Company_ID = Component_mast.Company_ID
and CFM.Component_ID = component_Mast.Component_ID
WHERE component_mast.component_name = '".$component_name."'
AND company_mast.company_name = '".$company_name."'";
SELECT * FROM `customfield_mast`
WHERE `company_id` =
(SELECT `id` FROM `company_mast` WHERE `company_name` = '$company_name')
AND `component_id` IN
(SELECT GROUP_CONCAT(`component_id`) FROM `component_mast`
WHERE `component_name` = '$component_name')

Categories