简体   繁体   English

SQL连接查询性能问题

[英]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])

But , 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)... 请注意,我只是从这3列中添加1( e.[IsPrimary]e.[IsVerified]e.[ModifiedDate] ),它的执行效果惊人(延迟5-6秒)...

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)... 而且,我没有很多记录...(约20条记录)...

UPDATE: 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 [UserID](ASC)-主键

  1. [User].[EmailAddresses] [用户]。[电子邮件地址]

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

[EmailAddress] (ASC) - Unique key [EmailAddress](ASC)-唯一键

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) . 您想尝试以下索引: users(password, userid)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. 我猜第一个查询能够使用索引作为覆盖索引来检索emailAddressID和emailAddress,但是第二个查询需要读取实际表,因为它返回不在索引中的列。 If you don't have emailAddressID and emailAddress indexed, try adding them as an index. 如果您没有为emailAddressID和emailAddress编制索引,请尝试将它们添加为索引。

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. 假设:EmailAddress是唯一的,因此该索引明确包含该字段以及EmailAddressID和UserID(如果它们是聚集索引)。 --OR-- - 要么 -

EmailAddressID and UserID are the PK and there is at least an index on EmailAddress. EmailAddressID和UserID是PK,并且EmailAddress上至少有一个索引。

When you add an additional field, that will lead to at least a seek+key lookup to retrieve the data from the table. 当您添加其他字段时,将至少导致一次seek + key查找,以从表中检索数据。

You may want an index containing the EmailAddress (since these are the field you are filtering by) and include the rest of the columns. 您可能需要一个包含EmailAddress的索引(因为这些是您要作为过滤依据的字段),并包括其余的列。 ( INCLUDE clause). INCLUDE子句)。 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. (可选)您可以尝试使用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! 而不是5秒的执行时间,它得到0.365,这太好了!

I didn't find anything wrong with my indexes, or in 1 of the 3 columns I added... 我的索引没有发现任何问题,也没有发现我添加的3列中的1列...

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])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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