SQL连接查询性能问题

时间:2017-07-28 01:58:40

标签: sql sql-server

我有两张桌子:

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

现在,当我运行此查询时,它表现得很棒:

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

但是,当我运行此查询时,它执行得非常糟糕:

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

请注意,我只是从这3列(e.[IsPrimary]e.[IsVerified]e.[ModifiedDate])中添加1,然后它会变得非常糟糕(延迟5-6秒)... < / p>

它可能是什么?我没有加入桌子吗?是因为我在两个表中都有一些同名的列?

另外,我没有很多记录......(大约20条记录)......

更新: 我发现&#34;(@ pPassword = u。[密码])&#34;也解决了这个问题,如果没有它,它会表现得很好,是否与索引有关?

这是执行计划:

Execution plan

我的索引:

  1. [用户] [用户]:
  2.   

    [UserID](ASC) - 主键

    1. [用户]。[EmailAddresses]
    2.   

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

           

      [EmailAddress](ASC) - 唯一键

5 个答案:

答案 0 :(得分:0)

对于此查询:

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

您想尝试以下索引:users(password, userid)email(emailaddress, userid)

答案 1 :(得分:0)

尝试运行解释或执行计划,看看它是如何执行的。解释计划将告诉您是否正在使用索引或表扫描。我猜第一个查询能够使用索引作为覆盖索引来检索emailAddressID和emailAddress,但是第二个查询需要读取实际表,因为它返回的列不在索引中。如果您没有索引emailAddressID和emailAddress,请尝试将它们添加为索引。

答案 2 :(得分:0)

也许不是一个好的解决方案,因为我无法测试,但尝试跟着看看会发生什么?

;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;

答案 3 :(得分:0)

您的第一个查询由索引覆盖,您的第二个查询不是。

假设:EmailAddress是唯一的,因此索引显式包含该字段加上EmailAddressID和UserID(如果它们是聚集索引)。 --OR -

EmailAddressID和UserID是PK,并且至少有一个关于EmailAddress的索引。

当您添加其他字段时,这将导致至少进行搜索+键查找以从表中检索数据。

您可能需要包含EmailAddress的索引(因为这些是您要过滤的字段)并包含其余列。 (INCLUDE条款)。这会使您的索引成为第二个查询的覆盖索引,因此索引扫描就足够了,不需要查找。

您可以选择使用UserID尝试类似的覆盖索引。

查询计划将有助于检查哪一个更好(对于您当前的数据)。检查一下。

答案 4 :(得分:0)

我找到了答案,虽然我不知道如果它是正确的,但似乎解决了这个问题,性能很棒!而不是5秒执行,它得到0.365,这太棒了!

我没有发现我的索引有任何问题,或者我添加的3列中的1列...

基本上,我更改了查询 - 我在查询中转了两个表,所以如果我有:

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

现在,它是:

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