简体   繁体   中英

SQL join query performance issue

I have two tables:

1. [User].[Users]

    --------------------------------------------------
    |[UserID]          | INT           (primary key) |
    |[Username]        | NVARCHAR(50)                |
    |[IsVerified]      | BIT                         |
    |[ModifiedDate]    | DATETIME                    |
    --------------------------------------------------

2. [User].[EmailAddresses]
    --------------------------------------------------
    |[UserID]          | INT          (foreign key)  |
    |[EmailAddressID]  | INT                         |
    |[EmailAddress]    | NVARCHAR(50)                |
    |[IsPrimary]       | BIT                         |
    |[IsVerified]      | BIT                         |
    |[ModifiedDate]    | DATETIME                    |
    --------------------------------------------------

Now, when I run this query, it performs great:

SELECT
  u.[UserID],
  u.[Username],
  u.[IsVerified],
  e.[EmailAddressID],
  e.[EmailAddress]
FROM [User].[Users] u
INNER JOIN [User].[EmailAddresses] e
  ON e.[UserID] = u.[UserID]
WHERE (@pEmailAddress = e.[EmailAddress])
AND (@pPassword = u.[Password])

, when I run this query, it performs horribly: ,当我运行此查询时,它的表现非常糟糕:

SELECT
  u.[UserID],
  u.[Username],
  u.[IsVerified],
  e.[EmailAddressID],
  e.[EmailAddress],
  e.[IsPrimary],
  e.[IsVerified],
  e.[ModifiedDate]
FROM [User].[Users] u
INNER JOIN [User].[EmailAddresses] e
  ON e.[UserID] = u.[UserID]
WHERE (@pEmailAddress = e.[EmailAddress])
AND (@pPassword = u.[Password])

Note that I just add 1 from these 3 columns ( e.[IsPrimary] , e.[IsVerified] , e.[ModifiedDate] ), and it turns to perform horribly (5-6 seconds delay)...

What could it be? am I not joining the tables right? is it because I have some columns with the same name in both tables?

Also, I don't have many records... (about 20 records)...

I found that "(@pPassword = u.[Password])" also removes the problem, it performs great without it, does it have something to do with indexing? 我发现“(@pPassword = u。[Password])”也消除了问题,如果没有它,它的执行效果很好,这与索引编制有关吗?

Here is the execution plan:

执行计划

My indexes:

  1. [User].[Users]:

[UserID] (ASC) - Primary key

  1. [User].[EmailAddresses]

[UserID] (ASC), [EmailAddressID] (ASC) - Primary key

[EmailAddress] (ASC) - Unique key

For this query:

SELECT u.[UserID], u.[Username], u.[IsVerified], e.[EmailAddressID],
       e.[EmailAddress], e.[IsPrimary], e.[IsVerified], e.[ModifiedDate]
FROM [User].[Users] u INNER JOIN
     [User].[EmailAddresses] e
      ON e.[UserID] = u.[UserID]
WHERE (@pEmailAddress = e.[EmailAddress]) AND (@pPassword = u.[Password]);

You want to try the following indexes: users(password, userid) and email(emailaddress, userid) .

Try running an explain or execution plan to see how it's executed. The explain plan will tell you whether indexes or table scans are being used. I am guessing the first query is able to use an index as a covered index to retrieve emailAddressID and emailAddress but the second query is required to read the actual table since it's returning columns not in the index. If you don't have emailAddressID and emailAddress indexed, try adding them as an index.

Perhaps not a good solution as I can't test that but try following to see what will happen?

;WITH CTE AS(
SELECT e.*
FROM [User].[Users] u
INNER JOIN [User].[EmailAddresses] e ON e.[UserID] = u.[UserID]
WHERE (@pEmailAddress = e.[EmailAddress]) AND (@pPassword = u.[Password])
)
SELECT [IsPrimary], [IsVerified], [ModifiedDate] 
FROM CTE;

Your first query is covered by indexes, your second is not.

Assumptions: EmailAddress is unique, thus that index explicitly contains that field plus EmailAddressID and UserID if they are the clustered index. --OR--

EmailAddressID and UserID are the PK and there is at least an index on EmailAddress.

When you add an additional field, that will lead to at least a seek+key lookup to retrieve the data from the table.

You may want an index containing the EmailAddress (since these are the field you are filtering by) and include the rest of the columns. ( INCLUDE clause). This would render your index a covering index for your second query, therefore an index scan would be enough and no need for lookup.

Optionally you can try a similar covering index using UserID.

A query plan will help a lot to check which one is better (for your current data). Check it.

I found an answer, though I don't if it's the right one, but seems to solve the issue, performance is great! instead of 5 seconds execution, it gets 0.365, this is great!

I didn't find anything wrong with my indexes, or in 1 of the 3 columns I added...

Basically, I changed the query - I turned both tables in the query, so if I had:

SELECT
  u.[UserID],
  u.[Username],
  u.[IsVerified],
  e.[EmailAddressID],
  e.[EmailAddress],
  e.[IsPrimary],
  e.[IsVerified],
  e.[ModifiedDate]
FROM [User].[Users] u
INNER JOIN [User].[EmailAddresses] e ON e.[UserID] = u.[UserID]
WHERE (@pEmailAddress = e.[EmailAddress]) AND (@pPassword = u.[Password])

Now, it is:

SELECT
  u.[UserID],
  u.[Username],
  u.[IsVerified],
  e.[EmailAddressID],
  e.[EmailAddress],
  e.[IsPrimary],
  e.[IsVerified],
  e.[ModifiedDate]
FROM [User].[EmailAddresses] e
INNER JOIN [User].[Users] u ON u.[UserID] = e.[UserID]
WHERE (e.[EmailAddress] = @pEmailAddress) AND (@pPassword = u.[Password])

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