tags:

views:

31

answers:

3

Hi, I have a join which deletes rows that match another table but the joining fields have to be a large varchar (250 chars). I know this isn't ideal but I can't think of a better way. Here's my query:

DELETE P 
FROM dbo.FeedPhotos AS P
INNER JOIN dbo.ListingPhotos AS P1 ON P.photo = P1.feedImage
INNER JOIN dbo.Listings AS L ON P.accountID = L.accountID
WHERE P.feedID = @feedID

This query is constantly timing out even though there are less than 1000 rows in the ListingPhotos table.

Any help would be appreciated.

A: 

Simply add an index.

Timothy Khouri
+3  A: 

I'd probably start by removing this line, as it doesn't seem to be doing anything:

INNER JOIN dbo.Listings AS L ON P.accountID = L.accountID

There might not be a lot of rows in ListingPhotos, but if there are a lot of rows in Listings then the join won't be optimized out.

Also check your indexing, as any join is bound to be slow without the appropriate indexes. Although you should generally try to avoid joining on character fields anyway, it's usually a sign that the data is not normalized properly.

Aaronaught
Joining on varchar is acceptable if it's the natural key and you haven't used a surrogate key (ask Joe Celko :-). You'll have to add a unique constraint or index on the varchar column if it was the unique value and you chose an int identity as the PK to keep data integrity
gbn
@gbn: If your natural key is 250 characters then it's time for a surrogate; somewhere there's a trade-off between the `INSERT`/`UPDATE`/`DELETE` performance hit of multiple indexes and the `SELECT` performance hit of a key more than 8 bytes long, but 250 is waaaay on the other side of the fence. Also, I wouldn't trust Joe Celko to correctly tell me the time of day. :P
Aaronaught
Agree to all of the above...
gbn
Thanks, I need to join on Listings because I only want to match photos on specific accounts. If there's a match on another account I don't want to delete it. I have however swapped the joins round so it does the accounts first, then added some indexes on accountID and feedImage. All seems to working well, for now...
CL4NCY
@CL4NCY: Doesn't seem to me that joining to another table is going to prevent deletion of photos attached to other accounts, unless you omitted a few lines of `WHERE/AND` from the original post. But in any case, if you had no indexes then that's definitely where the problem was; reordering your joins will normally have no effect at all, as the optimizer does its own rearranging anyway.
Aaronaught
@Aaronaught: Thanks, you're right I don't need the join on Listings.
CL4NCY
+1  A: 

I would consider:

  • rewriting to use EXISTS. This will stop processing if one row is found more reliably then relying on JOIN which may have many more intermediate rows (which is what Aaronaught said)

  • ensure all datatypes match exactly. All differences in length or type will mean no indexes will be used

  • speaking of which, do you have an index (rough guess) on feedid, photo and accountid?

Something like:

DELETE
    P 
FROM
    dbo.FeedPhotos AS P
WHERE
    P.feedID = @feedID
    AND
    EXISTS (SELECT * FROM
             dbo.ListingPhotos P1
           WHERE P.photo = P1.feedImage)
    AND
    EXISTS (SELECT * FROM
             dbo.Listings L
           WHERE P.accountID = L.accountID)
gbn