我有两张桌子:
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;也解决了这个问题,如果没有它,它会表现得很好,是否与索引有关?
这是执行计划:
我的索引:
[UserID](ASC) - 主键
[UserID](ASC),[EmailAddressID](ASC) - 主键
[EmailAddress](ASC) - 唯一键
答案 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])