2017-07-28 117 views
1

我有两个表:SQL连接查询性能问题

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列中加1(e.[IsPrimary]e.[IsVerified],e.[ModifiedDate]),并且它演变成可怕(延迟5-6秒)...

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

另外,我没有太多的记录...(约20条)...

UPDATE: 我发现 “(。@pPassword = U [密码])” 还删除这个问题,没有它就表现出色,它与索引有什么关系?

这里是执行计划:

Execution plan

我的索引:

  1. [用户] [用户]:

[用户名](ASC) - 主键

  • [用户] [EmailAddresses]
  • [用户名](ASC),[EmailAddressID](ASC) - 主键

    [EmailAddress的] (ASC) - 唯一键

    +0

    你检查过查询计划?在SQL Server Management Studio中,查询上方有一个按钮,可在执行后运行估计的计划。这将为您提供查询的可视化步骤,并按百分比向您显示查询中最昂贵的部分。它也会建议你应该创建的任何索引。请运行它,让我们知道它回来了。 – Dom

    +0

    @DomDaFonte谢谢,我添加了一个执行计划... –

    +0

    没问题。在您的查询计划中,我看到电话字段上有一个聚集索引扫描,尽管我看不到其中的电话号码。 1.为每个表运行sp_spaceused并发送结果。 2.你可以右键单击Ssms中的表,创建一个类似的并为每个表发布ddl? 3.最后是密码字段散列?我可能会在ddl中看到这个,但让我知道。 – Dom

    回答

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

    +0

    但是如果没有3列(例如[IsPrimary],例如[IsVerified],[[ModifiedDate])它表现很好,我认为它与索引无关,这些列不应该影响性能,但不知何故做... –

    0

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

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

    谢谢,我试过了,仍然拖延性能... –

    0

    你的第一个查询被索引覆盖,你的第二个查询不是。

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

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

    当您添加一个附加字段时,这将导致至少一次seek + key查找从表中检索数据。

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

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

    查询计划将有助于检查哪一个更好(针对当前数据)。核实。