简体   繁体   中英

SQL Query Between Dates AND Based on Employee Name

I have a SQL Azure database with two main tables that I am trying to join via a view. I have it working, but the execution time is in excess of 2 minutes.

Here are the main tables and columns I'm dealing with:

TransactionsTable:

PostedDate          | EmployeeFirstName | EmployeeLastName | DollarsCollected | UserName
---------------------------------------------------------------------------------------------
09/08/2017 09:05 am | 'John'            | 'Smith'          |            42.25 | 'john.smith'
09/08/2017 09:07 am | 'Jane'            | 'Jones'          |            58.50 | 'jane.jones'
09/08/2017 09:15 am | 'Tom'             | 'Holland'        |            62.75 | 'tom.holland' 
09/08/2017 09:17 am | 'John'            | 'Smith'          |            48.50 | 'john.smith'    
09/08/2017 09:19 am | 'Jane'            | 'Jones'          |            32.25 | 'jane.jones'

CustomerHistory

CustomerID | StartDate           | Duration | UserName      | TransactionType
-----------------------------------------------------------------------------
         1 | 09/08/2017 09:02 am |      600 | 'john.smit'h  | 'PropertyTax'
         2 | 09/08/2017 09:03 am |      500 | 'tom.holland' | 'TagRenewal'
         3 | 09/08/2017 09:04 am |      450 | 'jane.jones'  | 'PropertyTax'
         4 | 09/08/2017 09:12 am |      700 | 'john.smith'  | 'TagRenewal'
         5 | 09/08/2017 09:16 am |      300 | 'jane.jones'  | 'TagRenewal'

So, the deal here is - one employee can only have one customer at one time. If we know what time a transaction was posted and we know what employee posted it, then we should be able to connect that information to the CustomerHistory table by using the StartDate and StartDate + Duration as sort of an "umbrella" of the total transaction. Consider StartDate + Duration to be equal to EndDate . So, here's the query I'm trying to run to accomplish this:

SELECT
    *
FROM
    CustomerHistory
    JOIN TransactionsTable ON
        CustomerHistory.UserName = TransactionsTable.UserName
        AND
        TransactionsTable.PostedDate >= CustomerHistory.StartDate
        AND
        TransactionsTable.PostedDate <= DATEADD( ss, CustomerHistory.StartDate, CustomerHistory.Duration )

For reference, I have indexes on the UserName fields as well as the date fields. Suffice it to say I'm oversimplifying my tables here, as there are many more columns of data from each table I am hoping to join. I have run the execution plan in SQL Server, and it tells me that the Hash Match will take about 38% of my execution time, and the table scan on the transaction table will take 42%. I am decent with SQL but have never delved into a query quite as resource intensive as what I'm dealing with here, and its putting quite a load on my server trying to run it this way.

Can anyone help?

It's tricky to speed up because your query is non-SARGable. Adding a persisted computed column I believe should work quite well for your query. You will want to read up on it though because this can slow DML(inserts,updates, and deletes).

My creation scripts of your table for reference(SQL Fiddle http://sqlfiddle.com/#!6/f1a39/8 ):

Create Table dbo.TransactionsTable
(
  PostedDate Datetime,
  EmployeeFirstName Varchar(100),
  EmployeeLastName Varchar(100),
  DollarsCollected Money,
  UserName Varchar(100)
);

Create Table dbo.CustomerHistory
(
  CustomerID Int,
  StartDate DateTime,
  Duration Int,
  UserName Varchar(100),
  TransactionType Varchar(100)
);


Insert Into dbo.TransactionsTable
Values 
('09/08/2017 09:05 am','John','Smith',42.25 , 'john.smith'),
('09/08/2017 09:07 am','Jane','Jones',58.50 , 'jane.jones'),
('09/08/2017 09:15 am','Tom','Holland',62.75 , 'tom.holland'), 
('09/08/2017 09:17 am','John','Smith',48.50 , 'john.smith'),    
('09/08/2017 09:19 am','Jane','Jones',32.25 , 'jane.jones');
GO

Insert Into dbo.CustomerHistory
  Values (1,'09/08/2017 09:02 am',600,'john.smith' ,'PropertyTax'),
         (2,'09/08/2017 09:03 am',500,'tom.holland','TagRenewal'),
         (3,'09/08/2017 09:04 am',450,'jane.jones','PropertyTax'),
         (4,'09/08/2017 09:12 am',700,'john.smith','TagRenewal'),
         (5,'09/08/2017 09:16 am',300,'jane.jones','TagRenewal');
Go

Make sure you have this index.

CREATE NONCLUSTERED INDEX ix_test1
  ON TransactionsTable(UserName,PostedDate) 
  Include (EmployeeFirstName,EmployeeLastName,DollarsCollected);
GO

For customer history, can you add a persisted column? Then index the column

Alter Table CustomerHistory
Add EndDate As (DateAdd(ss,Duration,StartDate)) Persisted;
GO
CREATE NONCLUSTERED INDEX ix_test2
  ON CustomerHistory(UserName,StartDate,EndDate)
  Include(CustomerID,TransactionType);
GO

Here's the query

SELECT *
FROM CustomerHistory AS A
INNER JOIN TransactionsTable AS B
  ON A.UserName = B.UserName
  AND B.PostedDate Between A.StartDate And A.EndDate;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM