How to reduce execution time of a select query - sql

I have a query which is given below. My doubt is regarding its record fetching time. Is there any better way to fetch records than this method?
select product_code,product_name,price,taxPercentage,discount_type,discount_amount,prof it_type,profit_amount,purchase_code, qty
from (
select distinct p.product_code,p.product_name,pid.price,t.percentage as taxPercentage,p.discount_type,p.discount_amount,p.profit_type,p.profit_amount,
pu.purchase_code,pid.quantity+isnull(sum(sri.quantity),0) -isnull(sum(si.quantity),0) -isnull(sum(pri.quantity),0) as qty
from tbl_product p
left join tbl_purchase_item pid on p.product_code=pid.product_code
left join tbl_purchase pu on pu.purchase_code=pid.purchase_code
left join tbl_tax t on t.tax_code=p.tax_code
left join tbl_sale_item si on si.product_code=p.product_code
left join tbl_sale s on s.sale_code=si.sale_code
left join tbl_sale_return sr on sr.sale_code=s.sale_code
left join tbl_sale_return_item sri on sri.sale_return_code=sr.sale_return_code
left join tbl_purchase_return_item pri on pri.purchase_code=pu.purchase_code
group by p.product_code,p.product_name,pid.price,t.percentage,p.discount_type,p.discount_amount,p.profit_type,p.profit_amount,pu.purchase_code,pid.quantity
) as abc
where qty >0

I do not know how your database looks like. You have too many joins and I guess that is the root of the slowness.
First, make sure you have indexed all the columns used in the joins.
If that does not help, try to do some Denormalization. That way you will introduce some redundancy in your database, but the read time will improve.

Join Smaller table with larger table
consider an index on the table

Related

How to build a complex sql query?

Database design here
I want to get records from the product_spec_data table that are associated with products whose category_id is 5.
Please help me make a query to the database...
All of the relationship are clearly laid out, a simple join across tables would works.
SELECT psd.*
FROM product_spec_data psd
INNER JOIN product_spec_values psv ON psd.id = psv.product_spec_data_id
INNER JOIN products prod ON psv.product_id = prod.id
INNER JOIN categories cat ON prod.category_id = cat.id
-- with category id = 5
WHERE cat.id = 5;
I am not sure what do you mean by complex query. I guess your question is not complete. I think the query for your question (if it is T-SQL) will be as follows
select d.*
from product_spec_data d
left outer join product_spec_values v on d.id=v.product_spec_data_id
left outer join products p on v.product_id=p.id
where p.category_id=5
(I think in MySQL also above syntax will remain same, you may remove [outer] clause in MySQL)

Request Optimization (CTE, multiple LEFT JOIN, WHERE with OR)

Can anyone give me advice on how to optimize this request?
More left joins than in this example (20+), principally to get values with foreign key, what optimization is possible?
CTE used to create aggregates but CTE tables are used in principal request, so is it useful?
Where condition with a simple condition on the principal table and a second condition OR with fields of several tables, could it be better to add a column with a max date of the 3 fields and have a simple second condition (without OR)?
SQL Server 2015+
WITH
cte AS
(
SELECT
e_ofcte.id,
SUM(CASE WHEN f_ofcte.lib='G' THEN 1 ELSE 0 END) AS n1,
SUM(CASE WHEN f_ofcte.lib='H' THEN 1 ELSE 0 END) AS n2
FROM e_ofcte
INNER JOIN f_ofcte ON f_ofcte.id=e_ofcte.id
WHERE f_ofcte.lib IN ('G','H')
AND e_ofcte.date>=DATEFROMPARTS(YEAR(CURRENT_TIMESTAMP)-2,1,1)
GROUP BY
e_ofcte.id
)
SELECT
a.id,
b.sid,
c.sid,
cte.n1,
cte.n2
FROM a
LEFT JOIN cte ON a.id=cte.id
LEFT JOIN b ON a.id=b.id
LEFT JOIN c ON a.id=c.id
LEFT JOIN e_ofcte ON a.id=e_ofcte.id
LEFT JOIN i ON a.id=i.id
LEFT JOIN j ON a.id=j.id
LEFT JOIN f_ofcte ON a.id=f_ofcte.id
WHERE a.code='A'
AND
(
a.date>=>=DATEFROMPARTS(YEAR(CURRENT_TIMESTAMP)-2,1,1)
OR
b.date>=>=DATEFROMPARTS(YEAR(CURRENT_TIMESTAMP)-2,1,1)
OR
c.date>=>=DATEFROMPARTS(YEAR(CURRENT_TIMESTAMP)-2,1,1)
)
If you move "OR" conditions to JOIN it will return different results. My answer would be "NO", unless you exactly know what you are doing.
There are multiple possible approaches you can try to fight performance:
Move CTE to temporary table if you can. It makes query smaller?
which will help optimizer to come up with the best plan. Also, you
can tune two parts separately.
Possibly build filtered index on table A(id,date) with "WHERE
code='A'" - that would work if number of filtered records is
relatively small
Possibly build filtered index on table f_ofcte(id) with "WHERE
lib IN ('G','H')"
Build indexes on other tables on (id,date)
Not sure if you provided full query, but it looks like following
part is completely unused:
LEFT JOIN e_ofcte ON a.id=e_ofcte.id
LEFT JOIN i ON a.id=i.id
LEFT JOIN j ON a.id=j.id
LEFT JOIN f_ofcte ON a.id=f_ofcte.id

Number of rows reduced after join

I have a query that gives me 759 rows:
Select
buildingID
,buildingAddress
,building_zip
From
BuildingTable
However, when I join the table to get a column from another table, the number of rows is reduced to 707
Select
buildingID
,buildingaddress
,building_zip
,b.surveyCost
From
BuildingTable as A
Inner Join SurveyTable as B
On a.buildingAddress = b.address
What is the best way to test which rows I lost and why? and how do I prevent this from happening? I was thinking that maybe some of the buildings don't have survey costs and therefore it was only showing me the ones that have costs, but I see some null values there so that was not the issue, I think.
If you need extra information let me know. Thanks
To find the rows you have lost, just replace the inner join with a left join and look for missing rows:
Select bt.*
From BuildingTable bt left join
SurveyTable st
on bt.buildingAddress = st.address
where st.address is null;
Note that rows can also be duplicated in both tables, so you might have more missing rows than you expect.
You can find the row which rows are lost usig a left join between original query and resulting query where the join is nulll
Select
buildingID
,buildingAddress
,building_zip
From
BuildingTable t1
left join (
Select
buildingID
,buildingaddress
,building_zip
,b.surveyCost
From
BuildingTable as A
Inner Join SurveyTable as B
On a.buildingAddress = b.address
) t2 on t1.buildingID = t2.buildingID
where t2.buildingID is null
but why .. depend on you knowledge of the data

Joining of 5 Tables

I need to join 5 tables to get particular bill number.
Tables are
bill,
Service_bill
Damage_cost
Extraperson_cost
Advance_cost
Except bill, all other tables are may store null values.
My query is like below...
select bill.bill_no,
bill.total,
bill.discount,
bill.to_be_paid,
isnull(Service_bill.total_amt,0) as ServiceCharge,
isnull(Damage_cost.total_amt,0) as DamageCost,
isnull(Extraperson_cost.total_amt,0) as ExtraCost,
isnull(Advance_cost.total_amount,0) as Advance
from bill
left join Advance_cost on bill.bill_no=Advance_cost.room_bill_no and bill.bill_no='57'
inner join Service_bill on bill.bill_no=Service_bill.room_bill_no
inner join Damage_cost on bill.bill_no=Damage_cost.room_bill_no
inner join Extraperson_cost on bill.bill_no=Extraperson_cost.room_bill_no
Now it returns data's, which joins conditions are getting true.
First table should have values then other tables are null only so it must be return first tables completely. But i don't know why it comes like this!
The inner joins mean that you are only finding bills for people who have records in all 4 other tables. Use outer joins instead.
Also, you are limiting the results to those items where there is a record in "advance_cost" for bill 57. That's probaly not the idea...
Thanks Neville k... i got it using outer join...
select bill.bill_no,bill.total,bill.discount,bill.to_be_paid,
isnull(Service_bill.total_amt,0) as ServiceCharge,
isnull(Damage_cost.total_amt,0) as DamageCost,
isnull(Extraperson_cost.total_amt,0) as ExtraCost,
isnull(Advance_cost.total_amount,0) as Advance
from bill
left join Advance_cost on bill.bill_no=Advance_cost.room_bill_no
left outer join Service_bill on bill.bill_no=Service_bill.room_bill_no
left outer join Damage_cost on bill.bill_no=Damage_cost.room_bill_no
left outer join Extraperson_cost on bill.bill_no=Extraperson_cost.room_bill_no
where bill.bill_no='57'

When I add a LEFT OUTER JOIN, the query returns only a few rows

The original query returns 160k rows. When I add the LEFT OUTER JOIN:
LEFT OUTER JOIN Table_Z Z WITH (NOLOCK) ON A.Id = Z.Id
the query returns only 150 rows. I'm not sure what I'm doing wrong.
All I need to do is add a column to the query, which will bring back a code from a different table. The code could be a number or a NULL. I still have to display NULL, hence the reason for the LEFT join. They should join on the "id" columns.
SELECT <lots of stuff> + the new column that I need (called "code").
FROM
dbo.Table_A A WITH (NOLOCK)
INNER JOIN
dbo.Table_B B WITH (NOLOCK) ON A.Id = B.Id AND A.version = B.version
--this is where I added the LEFT OUTER JOIN. with it, the query returns 150 rows, without it, 160k rows.
LEFT OUTER JOIN
Table_Z Z WITH (NOLOCK) ON A.Id = Z.Id
LEFT OUTER JOIN
Table_E E WITH (NOLOCK) ON A.agent = E.agent
LEFT OUTER JOIN
Table_D D WITH (NOLOCK) ON E.location = D.location
AND E.type = 'Organization'
AND D.af_type = 'agent_location'
INNER JOIN
(SELECT X , MAX(Version) AS MaxVersion
FROM LocalTable WITH (NOLOCK)
GROUP BY agemt) P ON E.agent = P.location AND E.Version = P.MaxVersion
Does anyone have any idea what could be causing the issue?
When you perform a LEFT OUTER JOIN between tables A and E, you are maintaining your original set of data from A. That is to say, there is no data, or lack of data, in table E that can reduce the number of rows in your query.
However, when you then perform an INNER JOIN between E and P at the bottom, you are indeed opening yourself up to the possibility of reducing the number of rows returned. This will treat your subsequent LEFT OUTER JOINs like INNER JOINs.
Now, without your exact schema and a set of data to test against, this may or may not be the exact issue you are experiencing. Still, as a general rule, always put your INNER JOINs before your OUTER JOINs. It can make writing queries like this much, much easier. Your most restrictive joins come first, and then you won't have to worry about breaking any of your outer joins later on.
As a quick fix, try changing your last join to P to a LEFT OUTER JOIN, just to see if the Z join works.
You have to be very careful once you start with LEFT JOINs.
Let's suppose this model: You have tables Products, Orders and Customers. Not all products necessarily have been ordered, but every order must have customer entered.
Task: Show all products, and if the product was ordered, list the ordering customers; i.e., product without orders will be shown as one row, product with 10 orders will have 10 rows in the resultset. This calls for a query designed around FROM Products LEFT JOIN Orders.
Now someone could think "OK, Customer is always entered into orders, so I can make inner join from orders to customers". Wrong. Since the table Customers is joined through left-joined table Orders, it has to be left-joined itself... otherwise the inner join will propagate into the previous level(s) and as a result, you will lose all products that have no orders.
That is, once you join any table using LEFT JOIN, any subsequent tables that are joined through this table, need to keep LEFT JOINs. But it does not mean that once you use LEFT JOIN, all joins have to be of that type... only those that are dependent on the first performed LEFT JOIN. It would be perfectly fine to INNER JOIN the table Products with another table Category for example, if you only want to see Products which have a category set.
(Answer is based on this answer: http://www.sqlservercentral.com/Forums/Topic247971-8-1.aspx -> last entry)