I have a query for search function.
Basically search function allowed user to define what they "have" and "want". Then this query will filter out all the possible result which created by other user.
For example, I have apple (with good quality) and I want orange (with poor quality). So the result will display all user that have orange (with poor quality) and want apple (with good quality).
The search query a bit long and i try to simplify as below:
This stored procedure will receive user defined table (ItemID & Quality) as parameters
#WantUdt AS HaveItemUdt READONLY,
#HaveUdt AS HaveItemUdt READONLY
Search query (user can define more than one items and quality, so i use IN):
SELECT * from tbl_Trade WHERE TradeID IN
(SELECT TradeID from tbl_Want w INNER JOIN
(SELECT TradeID FROM tbl_Have
WHERE HaveID IN (SELECT ItemID FROM #HaveUdt) AND
Quality IN (SELECT QualityID FROM #HaveUdt)) as h --to filter [have],
ON w.TradeID = h.TradeID
WHERE WantID IN (SELECT ItemID FROM #WantUdt) AND
Quality =IN (SELECT QualityID FROM #WantUdt) --to filter [want]
)
Above query work as expected. However, I am having performance issue. I try do stress test by execute this stored procedure for multiple times within specific time (few seconds), and my db (SQL Server 2008 Express) seems can't effort and generate a timeout error
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
I guess it is because the query above use too many IN CLAUSE.
Is there any way to improve this query?
Try this. I hope it will help.
SELECT * -- select only those columns which are required
FROM tbl_Trade AS tt (NOLOCK)
INNER JOIN tbl_Want w(NOLOCK) ON tt.TradeId = w.TradeID
INNER JOIN tbl_Have h (NOLOCK) ON h.TradeID = w.TradeID
INNER JOIN #HaveUdt hu(NOLOCK) ON hu.itemId = h.HaveID AND hu.QualityId = h.Quality
INNER JOIN #WantUdt wu (NOLOCK) ON wu.ItemId = w.WantID AND wu.QualityId = w.Quality
Thanks
Related
I have a join that is returning multiple rows. I need to modify the code so it does not do so. I've figured out an extremely inefficient method, and was hoping someone could point me in the right direction.
My dataset consists of a list of 50 agents in an AGENT CTE who take technical support tickets stored in a TICKETS table. Agent info is stored in an employee table. I need to join the three objects so that each ticket is associated with it's agent. Agent ownership of a specific support call can be determined by one or more fields
-initial ticket responder
-ticket creator
-ticket owner
The complication is that 1 or more of my 50 agents can show up in any one of these three fields. Performing a join using this syntax results in duplicates.
with CTE_Agents as
(agent_name, agent_region) --defines in-scope agents and agent region for this project
select
fi.servicerequestnumber as In_Scope_Ticket
join vwdimemployee E1 (NOLOCK) on
E1.EmployeeDerivedID = fi.InitialResponseOwnerEmployeeDerivedID
or E1.employeederivedID = fi.creatoremployeederivedid
or e1.employeederivedid = fi.CurrentOwnerEmployeeDerivedID
join cte_agents ag on e1.EmployeeEmail = ag.agent
Because multiple in-scope agents can be in multiple join fields the above query returns duplicates. For example, if agent 1 is both the ticket creator and ticket owner I get 2 results back when I only want one. If agent 3 is the ticket owner and agent 4 is the ticket creator I also get that specific ticket twice in the result set.
In the case of such duplicates, I want to return a single row. My current solution is:
select
e1.employeename as InitalOwner
,e2.employeename as ticketcreator
,e3.employeename as ticketowner
join vwdimemployee E1 (NOLOCK) on E1.EmployeeDerivedID = st.InitialResponseOwnerEmployeeDerivedID
join vwdimemployee e2 (NOLOCK) on e2.employeederivedID = st.creatoremployeederivedid
join vwdimemployee e3 (NOLOCK) on e3.employeederivedID = st.CurrentOwnerEmployeeDerivedID
In the case of multiple results, I use this bit of code to give the current owner precedence. (results are pumped through multiple CTEs in order to do this).
isnull(initial_task_agent,isnull(creator_task_agent,current_task_agent)) as CCE_Agent
,isnull(initial_region,isnull(Creator_Region,Current_Region)) as CCE_Region
I would like a more efficient way to do this, but I can't figure out how. Any ideas are much appreciated.
You will find that COALESCE() works better than ISNULL() here:
coalesce(initial_task_agent,creator_task_agent,current_task_agent) as CCE_Agent
,coalesce(initial_region,Creator_Region,Current_Region) as CCE_Region
COALESCE() acts like ISNULL, but you can list more than 2 parameters. Other than that, it's not a bad approach.
If you are using MSSQL you probably can make a function ( or store procedure) make query faster because it precompilt.
something like:
CREATE FUNCTION [dbo].[func_get_emp]
(
#empID as int
)
RETURNS varchar
BEGIN
Declare #cRtn as varchar(100)
select #cRtn =employeename from vwdimemployee where employeederivedID = #empID
Return(#cRtn)
END
You can use that in query
select
dbo.func_get_emp(InitialResponseOwnerEmployeeDerivedID) as InitalOwner
,dbo.func_get_emp(creatoremployeederivedid) as ticketcreator
,dbo.func_get_emp(CurrentOwnerEmployeeDerivedID) as ticketowner
Stored procedure timing out because of being too slow, it could be because it's using outer full join
Error:
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The
timeout period elapsed prior to completion of the operation or the
server is not responding. ---> System.ComponentModel.Win32Exception
(0x80004005): The wait operation timed out at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection
Based on my research I think increasing time out may fix the error problem but then I want to decrease the time it takes to execute too, any improvement would be welcomed. I will post table structure if needed but that going to be a lot. Also I am not sure if increase time out is the best solution
/* Stored procedure to get fruits checks that the user has access to*/
ALTER procedure [dbo].[Fruits_GetChecksForUser]
(
#UserID VARCHAR(200),
#CheckUrlFilter varchar(256)
)
AS
SELECT Distinct
Fruits_Checks.*,
ManagementCommittees.Title As CommitteeName,
FruitCategories.ID As CategoryID,
FruitCategories.Title As CategoryName,
dbo.IsUserInGroup(#UserID, FruitCategories.FruitOfficerGroupID) AS IsUserFruitOfficer,
dbo.IsUserInGroup(#UserID, Fruits_Checks.AllocatedGroup) AS IsUserCheckResponsible,
Policies.CompanyID,
Policies.ID As PolicyID
FROM Groups_UserAccess
INNER JOIN FruitCategories_GroupAccess ON FruitCategories_GroupAccess.GroupID = Groups_UserAccess.GroupID
INNER JOIN FruitCategories ON FruitCategories.ID = FruitCategories_GroupAccess.FruitCategoryID
INNER JOIN Policies ON Policies.ID = FruitCategories.PolicyID
LEFT JOIN Policies_AppSettings ON Policies_AppSettings.PolicyID = Policies.ID
LEFT JOIN Clients_AppSettings ON Clients_AppSettings.ID = Policies.CompanyID
FULL OUTER JOIN Fruits ON Fruits.CategoryID = FruitCategories.ID
INNER JOIN Fruits_Checks ON Fruits_Checks.FruitID = Fruits.ID
INNER JOIN ManagementCommittees on Fruits_Checks.CommitteeID = ManagementCommittees.ID
WHERE
Fruits.ID IS NOT NULL
AND Fruits_Checks.URL LIKE '%' + #CheckUrlFilter + '%'
ORDER BY Fruits_Checks.EndDate
Increase of time is surely not a solution. It looks like innecessary/avoidable full outer join, distinct instruction and possibly inline function calls (would be fine to have a look into them too) slow donw your query drammaticaly.
At least an execution plan is required to provide you with more detailed answer.
Im running a query and its taking a long time. Here is my sample code:
SELECT #AppleCount=COUNT(*)
FROM (
SELECT * FROM #iDToStoreMapping sm
WHERE StoreFront=73
AND sm.CategoryCountryCategoryTYpeMappingID NOT IN
(SELECT * FROM #FinishedDls)
) rows
#AppleCount is supposed to be all the categoryCountryCategoryTypeMappingId's in existence and #FinishedDls has that id if an application finished its download and wrote that id in there, so this query is supposed to get the count of those ids which haven't downloaded yet. There's about 50k ids. and i have to run this query 3 times, but each one takes a couple mins. Is there anything im doing wrong?
Sometimes using an explicit join instead of not in results in better performance:
SELECT #AppleCount = COUNT(*)
FROM #iDToStoreMapping sm left outer join
#FinishedDls fd
on sm.CategoryCountryCategoryTYpeMappingID = fd.id
WHERE StoreFront = 73 and
fd.id is null;
I didnt use a primary key on my table variables and that is what caused the terrible performance. Sorry everyone.
I have two different queries which produce the same results. I wonder which one is more efficent. The second one, I am using one select clause less, but I am moving the where to the outter select. Which one is executed first? The left join or the where clause?
Using 3 "selects":
select * from
(
select * from
(
select
max(t.PRICE_DATETIME) over (partition by t.PRODUCT_ID) as LATEST_SNAPSHOT,
t.*
from
PRICE_TABLE t
) a
where
a.PRICE_DATETIME = a.LATEST_SNAPSHOT;
) r
left join
PRODUCT_TABLE l on (r.PRODUCT_ID = l.PRODUCT_ID and r.PRICE_DATETIME = l.PRICE_DATETIME)
Using 2 selects:
select * from
(
select
max(t.PRICE_DATETIME) over (partition by t.PRODUCT_ID) as LATEST_SNAPSHOT,
t.*
from
PRICE_TABLE t
) r
left join
PRODUCT_TABLE l on (r.PRODUCT_ID = l.PRODUCT_ID and r.PRICE_DATETIME = l.PRICE_DATETIME)
where
r.PRICE_DATETIME = r.LATEST_SNAPSHOT;
ps: I know, I know, "select star" is evil, but I'm writing it this way only here to make it smaller.
"I wonder which one is more efficent"
You can answer this question yourself pretty easily by turning on statistics.
set statistics io on
set statistics time on
-- query goes here
set statistics io off
set statistics time off
Do this for each of your two queries and compare the results. You'll get some useful output about how many reads SQL Server is doing, how many milliseconds each takes to complete, etc.
You can also see the execution plan SQL Server generates viewing the estimated execution plan (ctrl+L or right-click and choose that option) or by enabling "Display Actual Execution Plan" (ctrl+M) and running the queries. That could help answer the question about order of execution; I couldn't tell you off the top of my head.
I have a SQL Server 2008 database. This database has 2 tables:
Manufacturer
------------
ID,
Name nvarchar(256)
Product
-------
ID
ManufacturerID
Name nvarchar(256)
My application has a search box. I do not know if the user is going to provide a manufacturer name or a product name. In addition, I'm trying to be a little bit graceful and handle mis-spellings. In an effort to meet this criteria, I'm using the CONTAINSTABLE function. With this function, I have created the following query:
SELECT
*
FROM
[Manufacturer] m
INNER JOIN [Product] p ON m.[ID]=p.[ManufacturerID]
INNER JOIN CONTAINSTABLE(Manufacturer, Name, #searchQuery) r ON m.[ID]=r.[Key]
ORDER BY
r.[Rank]
My query is performing VERY SLOW with the CONTAINSTABLE function. Without the second INNER JOIN, the query runs in less than 1 second. With the second INNER JOIN included the query runs in a little over 30 seconds (too long).
Can anyone provide some performance recommendations? I have no clue how to overcome this hurdle.
Thank you,
Select just the fields you need, and not SELECT *.
Indexes on m and p are set?