Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Moving from MSDE 2000 to SQL 2008 Standard - slow stored procedures 3

Status
Not open for further replies.

Snakeroot

Technical User
Oct 4, 2006
112
US
I have an MSDE 2000 database with several databases and stored procedures that I've duplicated onto a new server.

The new server is Windows 2008 R2 running on VMWare vSphere 4. I've loaded SQL 2008 Standard SP1 onto this VM and copied all of the databases and stored procedures from MSDE 2000 to SQL 2008. I'm running through all the stored procedures to make sure they work before I point everything at the new server. Most stored procedures work just fine, however there are some that I'm having difficulty with.

Here's an example:
Code:
ALTER    PROCEDURE [dbo].[CR_AF_OutstandingCylinders]

	@BeginDate varchar(11) = '1/1/2007',
	@EndDate varchar(11) = '12/31/2007'

AS

DECLARE @InvoiceTable as varchar(255)
DECLARE @InvoiceLineDetailTable as varchar(255)
DECLARE @DROPCDView as varchar(1024), @DROPCMView as varchar(1024)
DECLARE @CREATECDView as varchar(2048), @CREATECMView as varchar(2048)

SET @DROPCDView = 'DROP VIEW CylinderDepositsView'

SET @CREATECDView = 'CREATE VIEW CylinderDepositsView AS
	SELECT AF_QB_invoicelinedetail.CustomField6 as CDSerialNum,
		CustomerRef_FullName as CDCustName,RefNumber as CDInvoiceNum,TxnDate as CDTxnDate, IsPaid,
		   AF_QB_invoicelinedetail.TxnLineID as CDTxnLineID, AF_QB_invoice.Franchise as CDFranchise
	FROM AF_QB_invoicelinedetail INNER JOIN AF_QB_invoice ON IDKEY = TxnID
	WHERE  (
		 (TxnDate >= ''' + @BeginDate + ''' AND TxnDate <= ''' + @EndDate + ''')
			AND 
		(TemplateRef_FullName = ''Cylinder Deposit'')
			AND
		(CustomerRef_FullName <> ''Miscellaneous'')
			AND
		(ItemRef_FullName = ''Cylinder Deposit'')
		   )
	'

If object_ID('RRCorp..CylinderDepositsView')IS NOT NULL
	BEGIN
		PRINT 'CylinderDepositsView Exists!'
		exec(@DROPCDView)
		PRINT 'CylinderDepositsView Deleted!'
		exec(@CREATECDView)
		PRINT 'CylinderDepositsView Created!'
	END
ELSE
	BEGIN	
		PRINT 'CylinderDepositsView does not exist.  Creating CylinderDepositsView...'	
		exec(@CREATECDView)
		PRINT 'CylinderDepositsView Created!'
END

SET @DROPCMView = 'DROP VIEW CylinderReturnsView'

SET @CREATECMView = 'CREATE VIEW CylinderReturnsView AS
SELECT AF_QB_creditmemolinedetail.CustomField6 as CMSerialNum,
	CustomerRef_FullName as CMCustName, RefNumber as CMCreditMemoNum,TxnDate as CMTxnDate, CreditRemaining,
       AF_QB_creditmemolinedetail.TxnLineID as CMTxnLineID, AF_QB_creditmemo.Franchise as CMFranchise
FROM AF_QB_creditmemolinedetail INNER JOIN AF_QB_creditmemo ON IDKEY = TxnID 
WHERE  (
	 (TxnDate >= ''' + @BeginDate + ''' AND TxnDate <= ''' + @EndDate + ''')
		AND 
	(TemplateRef_FullName = ''Cylinder Deposit - Credit Memo'')
		AND
	(CustomerRef_FullName <> ''Miscellaneous'')
		AND
	(ItemRef_FullName = ''Cylinder Deposit'')
       )
'

If object_ID('RRCorp..CylinderReturnsView')IS NOT NULL
	BEGIN
		PRINT 'CylinderReturnsView Exists!'
		exec(@DROPCMView)
		PRINT 'CylinderReturnsView Deleted!'
		exec(@CREATECMView)
		PRINT 'CylinderReturnsView Created!'
	END
ELSE
	BEGIN	
		PRINT 'Creating CylinderReturns View...'	
		exec(@CREATECMView)
		PRINT 'CylinderReturnsView Created!'
END


DECLARE @Reconcile TABLE (InvoiceNum varchar(255), CreditMemoNum varchar(255), SerialNum varchar(50), InvoiceLineTxnLineID varchar(255), 
CreditMemoTxnLineID varchar(255), IsPaid bit, Franchise varchar(50))

INSERT @Reconcile (InvoiceNum,CreditMemoNum,SerialNum,InvoiceLineTxnLineID,CreditMemoTxnLineID,IsPaid,Franchise)

SELECT CDInvoiceNum as InvoiceNum, CMCreditMemoNum as CreditMemoNum, CDSerialNum as SerialNum, 
       CDTxnLineID as InvoiceTxnLineID, CMTxnLineID as CreditMemoTxnLineID, IsPaid, CDFranchise As Franchise FROM CylinderDepositsView CD
INNER JOIN CylinderReturnsView CM
ON CD.CDSerialNum = CM.CMSerialNum
WHERE  CD.CDCustName = CM.CMCustName AND CMTxnDate >= CDTxnDate AND CD.CDFranchise = CM.CMFranchise




-- This Query shows the serial #'s that haven't been picked up
select DISTINCT CDSerialNum,
				CDCustName,
				CDInvoiceNum,
				CDTxnDate,
				CDTxnLineID, 
				CD.IsPaid, 
				CD.CDFranchise 
from CylinderDepositsView CD, @Reconcile RC
where (RC.Franchise = CD.CDfranchise AND CDSerialNum IN 
			(select CMSerialNum 
				from CylinderReturnsView 
				WHERE CD.CDTxnDate > CMTxnDate AND CDTxnLineID NOT IN (Select InvoiceLineTxnLineID from @Reconcile))) 
				OR 
				(CDSerialNum NOT IN (select CMSerialNum from CylinderReturnsView) OR (CDTxnLineID NOT IN (Select InvoiceLineTxnLineID from @Reconcile)))

When I run this on the server with 2000 using the parameters of '1/1/2007', '5/1/2007' it takes 38 seconds to run. When I run this on the server with 2008 using the same parameters, it takes 39 seconds to run. However, if I run this on the server with 2000 using normal parameters such as '1/1/2007', '12/23/2009' it takes 4 minutes 38 seconds. When I run '1/1/2007', '12/23/2009' on the new 2008 server, it takes well over 45 minutes (I haven't let it run all the way out because 45 minutes is way too long).

It appears that this part of the above stored procedure is what is taking so long:

Code:
select DISTINCT CDSerialNum,
				CDCustName,
				CDInvoiceNum,
				CDTxnDate,
				CDTxnLineID, 
				CD.IsPaid, 
				CD.CDFranchise 
from CylinderDepositsView CD, @Reconcile RC
where (RC.Franchise = CD.CDfranchise AND CDSerialNum IN 
			(select CMSerialNum 
				from CylinderReturnsView 
				WHERE CD.CDTxnDate > CMTxnDate AND CDTxnLineID NOT IN (Select InvoiceLineTxnLineID from @Reconcile))) 
				OR 
				(CDSerialNum NOT IN (select CMSerialNum from CylinderReturnsView) OR (CDTxnLineID NOT IN (Select InvoiceLineTxnLineID from @Reconcile)))

The above code produces the answers I am looking for. I'm wondering if anyone knows of a better way to go about this, or if there is something unique to SQL 2008 that makes this slower? I'm at a loss. Thanks for any help you can provide.

 
If anything, SQL2008 should be faster than SQL2000. When it's not faster, you can usually blame your statistics.


And yeah.... try re-writing the query to remove the IN stuff. It'll probably execute faster.

-George

"The great things about standards is that there are so many to choose from." - Fortune Cookie Wisdom
 
Don't make it too fast though... you don't want your boss to regret purchasing the new hardware and software.

-George

"The great things about standards is that there are so many to choose from." - Fortune Cookie Wisdom
 
Thanks for the suggestions George. I updated statistics, but there's still something else going on. I ran with client statistics to see if that might be helpful. Here's the result on the 2000 machine:

Code:
Application Profile Statistics		
  Timer resolution (milliseconds)	0	
  Number of INSERT, UPDATE, DELETE statements	2	
  Rows effected by INSERT, UPDATE, DELETE statements	485
  Number of SELECT statements	0	
  Rows effected by SELECT statements	0	
  Number of user transactions	30	
  Average fetch time	0	
  Cumulative fetch time	0	
  Number of fetches	0	
  Number of open statement handles	0	
  Max number of opened statement handles	0	
  Cumulative number of statement handles	0	
 		
Network Statistics		
  Number of server roundtrips	3	
  Number of TDS packets sent	3	
  Number of TDS packets received	67	
  Number of bytes sent	250	
  Number of bytes received	264774	
 		
Time Statistics		
  Cumulative client processing time	2	
  Cumulative wait time on server replies	1025

Same query on 2008 with client stats:

Code:
Client Execution Time	14:20:58	
Query Profile Statistics		
  Number of INSERT, DELETE and UPDATE statements	2	
  Rows affected by INSERT, DELETE, or UPDATE statements	414	
  Number of SELECT statements 	7	
  Rows returned by SELECT statements	185	
  Number of transactions 	2	
Network Statistics		
  Number of server roundtrips	3	
  TDS packets sent from client	3	
  TDS packets received from server	210	
  Bytes sent from client	322	
  Bytes received from server	851760	
Time Statistics		
  Client processing time	273983	
  Total execution time	278309	
  Wait time on server replies	4326

I also noticed that if I first run on the 2000 server with parameters of say '1/1/2007','5/1/2007', and then run a subsequent time with the parameters of '1/1/2007','7/1/2007', the results come back in less than 10 seconds. But when I increae the date range of the parameters on the 2008 server to '1/1/2007','7/1/2007', the run time gets increasingly longer the more the dates span.

As far as re-writing without the IN statements, I'd be indebted to anyone who could put me on the right path in terms of doing that. I'm not great at SQL. I know just enough to be dangerous :)

 
As far as re-writing without the IN statements, I'd be indebted to anyone who could put me on the right path in terms of doing that. I'm not great at SQL. I know just enough to be dangerous

My problem is... I almost never use the IN statement because most of the time performance suffers. So... I'm sitting here staring at this "beast of a SQL" and scratching my head. We have IN's buried a couple deep and some of them are NOT IN. Urgh.

Can you post some sample data from the 3 tables/views involved? @Reconcile, CylinderDepositsView, and CynlinderReturnsView. Do NOT post any confidential data. Replace with dummy data. Then, post the expected output from the sample data that you post. This will make it a lot easier for us to help you.

-George

"The great things about standards is that there are so many to choose from." - Fortune Cookie Wisdom
 
Fair enough :) Here's the needed info:

Code:
CylinderDepositsView						
						
CDSerialNum	CDCustName	CDInvoiceNum	CDTxnDate	IsPaid	CDTxnLineID	CDFranchise
42051C	AMI	29356CD	4/22/2009	1	20351-1240578902	C
45367C	ASHAC	33001CD	1/19/2009	1	40DC6-1232565201	N
51477C	AMS	33037CD	3/4/2009	1	42957-1236213617	N
45465C	AMS	33331CD	1/16/2009	1	40B84-1232390165	N 
12784C	AMS	33331CD	1/16/2009	1	40B85-1232390165	N
45573C	AMS	33331CD	1/16/2009	1	40B86-1232390165	N
45467C	ASI	29163CD	1/27/2009	1	413FE-1233164898	N
45585C	ASI	29163CD	1/27/2009	1	41400-1233164898	N
45724C	ASI	29163CD	1/27/2009	1	41401-1233164898	N
44522C	ASI	29163CD	1/27/2009	1	413FF-1233164898	N
45411C	BAMS	24809CD	4/30/2009	1	C374-1241437948	B
053659C	BAMS	24809CD	4/30/2009	1	C375-1241437948	B
45352C	BAMS	24809CD	4/30/2009	1	C376-1241437948	B
51673C	BAMS	24809CD	4/30/2009	1	C373-1241437948	B
42051C	T	88888CD	5/1/2009	1	8888-8888888888	B
42051C	Z	99999CD	12/10/2009	0	9999-9999999999	B

Code:
CylinderRentalsView

CMSerialNum	CMCustName	CMCreditMemoNum	CMTxnDate	CreditRemaining	CMTxnLineID	CMFranchise
51673C	BAMS	24809CM	5/14/2009	0	C760-1242319194	B
053659C	BAMS	24809CM	5/14/2009	0	C762-1242319194	B
45411C	BAMS	24809CM	5/14/2009	0	C761-1242319194	B
45352C	BAMS	24809CM	5/14/2009	0	C763-1242319194	B
42051C	AMI	27728CM	9/1/2009	0	2538B-1251831945	C
45585C	ASI	33432CM	2/19/2009	0	42151-1235088506	N
45467C	ASI	33432CM	2/19/2009	0	4214F-1235088506	N
45724C	ASI	33432CM	2/19/2009	0	42152-1235088506	N
45367C	ASHAC	33418CM	1/21/2009	0	40E62-1232649007	N
45465C	AMS	33417CM	1/21/2009	0	40E6D-1232649203	N
12784C	AMS	33417CM	1/21/2009	0	40E6E-1232649203	N
45573C	AMS	33417CM	1/21/2009	0	40E6F-1232649203	N
44522C	ASI	33432CM	2/19/2009	0	42150-1235088506	N
51477C	AMS	33042CM	3/6/2009	0	429FB-1236379839	N
42051C	T	12345CM	5/5/2009	0	00000-0000000000	B

Code:
@Reconcile

InvoiceNum	CreditMemoNum	SerialNum	InvoiceLineTxnLineID	CreditMemoTxnLineID	IsPaid	Franchise
24809CD	24809CM	45411C	C374-1241437948	C761-1242319194	1	B
24809CD	24809CM	053659C	C375-1241437948	C762-1242319194	1	B
24809CD	24809CM	51673C	C373-1241437948	C760-1242319194	1	B
24809CD	24809CM	45352C	C376-1241437948	C763-1242319194	1	B
29163CD	33432CM	45467C	413FE-1233164898	4214F-1235088506	1	N
29163CD	33432CM	44522C	413FF-1233164898	42150-1235088506	1	N 
29163CD	33432CM	45585C	41400-1233164898	42151-1235088506	1	N
29163CD	33432CM	45724C	41401-1233164898	42152-1235088506	1	N
29356CD	27728CM	42051C	20351-1240578902	2538B-1251831945	1	C 
33001CD	33418CM	45367C	40DC6-1232565201	40E62-1232649007	1	N
33037CD	33042CM	51477C	42957-1236213617	429FB-1236379839	1	N
33331CD	33417CM	12784C	40B85-1232390165	40E6E-1232649203	1	N
33331CD	33417CM	45465C	40B84-1232390165	40E6D-1232649203	1	N
33331CD	33417CM	45573C	40B86-1232390165	40E6F-1232649203	1	N

Here's how it works...

An item (or multiple items) get dropped off and the serial of each item gets entered on an invoice. This is what you're seeing on the CylinderDepositsView.

An item (or mulitple items) get picked up and the serial of each item gets entered on a credit memo. This is what you're seeing on the CylinderRentalsView.

If an item is on the CylinderDepositsView and is then on the CylinderRentalsView with a CMTxnDate later (or same day) than the CDTxnDate on the CylinderDepositsView, then that item was picked up and that information should be displayed on the @Reconcile table. The @Reconcile table shows the CD Invoice number (when the item was dropped off), the CM number (when the item was picked up), the serial num of the item (and other information needed on the report).


Each item is dropped off one day and picked up another day (or possibly same day). If there is no credit memo on the same day or after the date of the drop off, then the item is assumed to still be out (not picked up yet).

This is the information I'm looking for. What items have not been picked up yet.

Using the tables above, here's what the result would look like:

Code:
CDSerialNum	CDCustName	CDInvoiceNum	CDTxnDate	CDTxnLineID	IsPaid	CDFranchise
42051C	Z	99999CD	12/10/2009	9999-9999999999	0	B

I don't have to do anything the same way I'm currently doing. That was just the only way I able to get it to work. Now that it's slower than molasses, I need to find a better way.

Again, I appreciate any help to get me on the right track to get rid of all the "IN" statements.
 
I'm a little skeptical of the query below because it seems a little too simple to replace all the conditions you had with the IN stuff. Based on your sample data, it does return the correct data though, so it's at least a start.

In the code below, you can see that I am creating a couple table variables and hard coding your data in to it. This is only so that I can test the code I wrote. You can copy/paste this to a query window and run it to see how it works. If you are satisfied with it, remove the table variable stuff and replace with your real tables instead.

Code:
Declare @CylinderDepositsView 
Table   (CDSerialNum varchar(20), CDCustName varchar(20),CDInvoiceNum varchar(20),
        CDTxnDate DateTime, IsPaid bit, CDTxnLineID varchar(20), CDFranchise varchar(20))

Insert Into @CylinderDepositsView Values('42051C','AMI','29356CD','4/22/2009','1','20351-1240578902','C')
Insert Into @CylinderDepositsView Values('45367C','ASHAC','33001CD','1/19/2009','1','40DC6-1232565201','N')
Insert Into @CylinderDepositsView Values('51477C','AMS','33037CD','3/4/2009','1','42957-1236213617','N')
Insert Into @CylinderDepositsView Values('45465C','AMS','33331CD','1/16/2009','1','40B84-1232390165','N')
Insert Into @CylinderDepositsView Values('12784C','AMS','33331CD','1/16/2009','1','40B85-1232390165','N')
Insert Into @CylinderDepositsView Values('45573C','AMS','33331CD','1/16/2009','1','40B86-1232390165','N')
Insert Into @CylinderDepositsView Values('45467C','ASI','29163CD','1/27/2009','1','413FE-1233164898','N')
Insert Into @CylinderDepositsView Values('45585C','ASI','29163CD','1/27/2009','1','41400-1233164898','N')
Insert Into @CylinderDepositsView Values('45724C','ASI','29163CD','1/27/2009','1','41401-1233164898','N')
Insert Into @CylinderDepositsView Values('44522C','ASI','29163CD','1/27/2009','1','413FF-1233164898','N')
Insert Into @CylinderDepositsView Values('45411C','BAMS','24809CD','4/30/2009','1','C374-1241437948','B')
Insert Into @CylinderDepositsView Values('053659C','BAMS','24809CD','4/30/2009','1','C375-1241437948','B')
Insert Into @CylinderDepositsView Values('45352C','BAMS','24809CD','4/30/2009','1','C376-1241437948','B')
Insert Into @CylinderDepositsView Values('51673C','BAMS','24809CD','4/30/2009','1','C373-1241437948','B')
Insert Into @CylinderDepositsView Values('42051C','T','88888CD','5/1/2009','1','8888-8888888888','B')
Insert Into @CylinderDepositsView Values('42051C','Z','99999CD','12/10/2009','0','9999-9999999999','B')

Declare @CylinderRentalsView 
Table   (CMSerialNum VarChar(20),   CMCustName VarChar(20),    CMCreditMemoNum VarChar(20),
        CMTxnDate DateTime, CreditRemaining VarChar(20), CMTxnLineID VarChar(20),   CMFranchise VarChar(20))

Insert into @CylinderRentalsView Values('51673C','BAMS','24809CM','5/14/2009','0','C760-1242319194','B')
Insert into @CylinderRentalsView Values('053659C','BAMS','24809CM','5/14/2009','0','C762-1242319194','B')
Insert into @CylinderRentalsView Values('45411C','BAMS','24809CM','5/14/2009','0','C761-1242319194','B')
Insert into @CylinderRentalsView Values('45352C','BAMS','24809CM','5/14/2009','0','C763-1242319194','B')
Insert into @CylinderRentalsView Values('42051C','AMI','27728CM','9/1/2009','0','2538B-1251831945','C')
Insert into @CylinderRentalsView Values('45585C','ASI','33432CM','2/19/2009','0','42151-1235088506','N')
Insert into @CylinderRentalsView Values('45467C','ASI','33432CM','2/19/2009','0','4214F-1235088506','N')
Insert into @CylinderRentalsView Values('45724C','ASI','33432CM','2/19/2009','0','42152-1235088506','N')
Insert into @CylinderRentalsView Values('45367C','ASHAC','33418CM','1/21/2009','0','40E62-1232649007','N')
Insert into @CylinderRentalsView Values('45465C','AMS','33417CM','1/21/2009','0','40E6D-1232649203','N')
Insert into @CylinderRentalsView Values('12784C','AMS','33417CM','1/21/2009','0','40E6E-1232649203','N')
Insert into @CylinderRentalsView Values('45573C','AMS','33417CM','1/21/2009','0','40E6F-1232649203','N')
Insert into @CylinderRentalsView Values('44522C','ASI','33432CM','2/19/2009','0','42150-1235088506','N')
Insert into @CylinderRentalsView Values('51477C','AMS','33042CM','3/6/2009','0','429FB-1236379839','N')
Insert into @CylinderRentalsView Values('42051C','T','12345CM','5/5/2009','0','00000-0000000000','B')

Select D.*
From   @CylinderDepositsView D
       Left Join @CylinderRentalsView R
          On D.CDSerialNum = R.CMSerialNum
          And D.CDTXNDate <= R.CMTxnDate
          And D.CDFranchise = R.CMFranchise
          And D.CDCustName = R.CMCustName
Where  R.CMSerialNum Is NULL

The trick here is.... the LEFT JOIN and the IS NULL check.

First, notice that the D table is to the left of the LEFT JOIN code, and the R table is on the right. Position matters. Now, since this is a left join, the query will return all the rows from the table on the left. If there is a matching rows from the right table (based on the ON clause criteria), you will get the data. If there is no match, there will not be any data in those columns, and you will get all NULL's instead of data.

Since we want to get rows from left table that does NOT have a match with rows on the right table, we filter (WHERE clause) on any column from the right table being NULL.

The concept of LEFT JOIN is so important, that I'll help explain it with an example.

Suppose you had the following tables.

[tt][blue]
[!]People[/!]
PersonId Name
----------- --------------------
1 Santa
2 Frosty
3 Rudolph


[!]FavoriteColor[/!]
PersonId Color
----------- --------------------
2 White
3 Red
[/blue][/tt]

Now, suppose we wanted to find all people without a favorite color. How would we do this? There are actually 5 (or more) ways to do this.


For the purposes of this discussion, let's just stay focused on the IN vs. Left Join method.

Do this: open a query window and copy/paste this code.

Code:
Declare @People Table(PersonId Int, Name VarChar(20))

Insert Into @People Values(1,'Santa')
Insert Into @People Values(2,'Frosty')
Insert Into @People Values(3,'Rudolph')

Declare @FavoriteColors Table(PersonId Int, Color VarChar(20))
Insert Into @FavoriteColors Values(2, 'White')
Insert Into @FavoriteColors Values(3, 'Red')

Now, if we write an inner join query, Santa won't show up because he does not have a row in the FavoriteColors table.

Code:
Select * 
From   @People P
       Inner Join @FavoriteColors C
          On P.PersonId = C.PersonId
[tt][blue]
PersonId Name PersonId Color
----------- -------------------- ----------- --------------
2 Frosty 2 White
3 Rudolph 3 Red
[/blue][/tt]

If we write a left join query, we will get this:

Code:
Select * 
From   @People P
       Left Join @FavoriteColors C
          On P.PersonId = C.PersonId
[tt][blue]
PersonId Name PersonId Color
----------- ---------- ----------- ----------
1 Santa [!]NULL NULL[/!]
2 Frosty 2 White
3 Rudolph 3 Red
[/blue][/tt]
Notice that we now get Santa, but with nulls in the color columns.

Now, if we want to ONLY return that one row, we can add a where clause condition, like this:

Code:
Select * 
From   @People P
       Left Join @FavoriteColors C
          On P.PersonId = C.PersonId
Where  C.PersonId Is NULL
[tt][blue]
PersonId Name PersonId Color
----------- ---------- ----------- ----------
1 Santa NULL NULL
[/blue][/tt]

The IN query would look like this:
Code:
Select *
From   @People
Where  PersonId Not In (Select PersonId From @FavoriteColors)
[tt][blue]
PersonId Name PersonId Color
----------- ---------- ----------- ----------
1 Santa NULL NULL
[/blue][/tt]

Notice that it produces the same results as the left join query. In my opinion, the LEFT JOIN query is easier to read and understand. In my experience, LEFT JOIN queries usually perform better because they make better use of existing indexes and the SQL Query optimizer usually creates better execution plans for it.

In the example above, both queries create the exact same execution plan, so both will execute in the same amount of time. As your queries get more complicated, the LEFT JOIN query usually performs better.

Make sense?

-George

"The great things about standards is that there are so many to choose from." - Fortune Cookie Wisdom
 
George! WOW! That cut down the time from over an hour to about 3 seconds. That's incredible!

I really appreciate you taking the time to teach me how it works as well. I'm going to have to go through that several times so that it becomes familiar to me and then I can use it for other queries.

Again, many thanks!
 
It's a Christmas miracle!

Actually, the concept of join is so fundamental and so important, that I recommend you stop coding now until you understand how this works and also how you can make it work for you. There's actually more join types than this. There's Inner Join, Left Join, Right Join, Full Join and Cross Join. In a properly normalized database, most of your queries will use inner joins. Left joins are not uncommon at all. Right join is is the same thing as a left join. In fact... don't use a right join, it just makes the query more complicated. Full join are very rare. I don't think I have a single full join query in all of my production code. Cross joins can come in handy some times, but you need to be extremely careful when you use it because you could end up with many more rows than you expect. Do a google search on [google]SQL Join Fundamentals[/google]. Keep reading articles you find until it completely makes sense. You'll be glad you did.


-George

"The great things about standards is that there are so many to choose from." - Fortune Cookie Wisdom
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top