如何优化缓慢的SQL查询?

如何优化缓慢的SQL查询?,sql,sql-server,Sql,Sql Server,我有两张桌子。第一个“用户”表由记录用户登录事件的行组成。该表如下所示: LoginTable LoginID Name Time 100 Joe 12:00pm 101 Bob 3:30pm 102 Joe 4:00pm 103 Sue 6:15pm MetricsTable MetricID LoginID Label Data 500 100 IPAddre

我有两张桌子。第一个“用户”表由记录用户登录事件的行组成。该表如下所示:

LoginTable
LoginID   Name    Time
100       Joe     12:00pm
101       Bob     3:30pm
102       Joe     4:00pm
103       Sue     6:15pm
MetricsTable
MetricID  LoginID   Label       Data
500       100       IPAddress   1.2.3.4
501       100       Attempts    25       
502       100       Status      Good
503       101       IPAddress   1.2.3.5
504       101       Attempts    19       
505       101       Status      Bad
506       102       IPAddress   1.2.3.6
507       102       Attempts    35       
508       102       Status      Hold
509       103       IPAddress   1.2.3.7
510       103       Attempts    4       
511       103       Status      Trial
SELECT LoginTable.LoginID, LoginTable.Name, LoginTable.Time, 
(SELECT MetricsTable.Data FROM MetricsTable WHERE
 MetricsTable.LoginID=LoginTable.LoginID and 
 MetricsTable.Label="IPAddress") as IPAddressEx
FROM LoginTable
LoginID   Name    Time   IP  Attempts  Status FutureColumn1 FutureColumn2 ...
第二个表记录了关于每个登录的附加指标,虽然不常见,但记录的附加项的数量可能会发生变化。该表如下所示:

LoginTable
LoginID   Name    Time
100       Joe     12:00pm
101       Bob     3:30pm
102       Joe     4:00pm
103       Sue     6:15pm
MetricsTable
MetricID  LoginID   Label       Data
500       100       IPAddress   1.2.3.4
501       100       Attempts    25       
502       100       Status      Good
503       101       IPAddress   1.2.3.5
504       101       Attempts    19       
505       101       Status      Bad
506       102       IPAddress   1.2.3.6
507       102       Attempts    35       
508       102       Status      Hold
509       103       IPAddress   1.2.3.7
510       103       Attempts    4       
511       103       Status      Trial
SELECT LoginTable.LoginID, LoginTable.Name, LoginTable.Time, 
(SELECT MetricsTable.Data FROM MetricsTable WHERE
 MetricsTable.LoginID=LoginTable.LoginID and 
 MetricsTable.Label="IPAddress") as IPAddressEx
FROM LoginTable
LoginID   Name    Time   IP  Attempts  Status FutureColumn1 FutureColumn2 ...
我试图构建一个LoginTable查询,该查询将为每一行显示表示与每个登录事件关联的额外度量数据的附加列

一种解决方案是这样做:

LoginTable
LoginID   Name    Time
100       Joe     12:00pm
101       Bob     3:30pm
102       Joe     4:00pm
103       Sue     6:15pm
MetricsTable
MetricID  LoginID   Label       Data
500       100       IPAddress   1.2.3.4
501       100       Attempts    25       
502       100       Status      Good
503       101       IPAddress   1.2.3.5
504       101       Attempts    19       
505       101       Status      Bad
506       102       IPAddress   1.2.3.6
507       102       Attempts    35       
508       102       Status      Hold
509       103       IPAddress   1.2.3.7
510       103       Attempts    4       
511       103       Status      Trial
SELECT LoginTable.LoginID, LoginTable.Name, LoginTable.Time, 
(SELECT MetricsTable.Data FROM MetricsTable WHERE
 MetricsTable.LoginID=LoginTable.LoginID and 
 MetricsTable.Label="IPAddress") as IPAddressEx
FROM LoginTable
LoginID   Name    Time   IP  Attempts  Status FutureColumn1 FutureColumn2 ...
该查询将显示一个额外的列,其中显示为该事件记录的“IPAddress”值。然后,我可以再添加两个子查询,以显示“尝试”和“状态”的附加列(请注意,这些只是假的示例)。我不关心是否能够自动识别更多的潜在列,如果它们出现,我可以手动添加它们。然而,这种为每一个额外列添加子查询的技术似乎非常缓慢

实现这一目标的更好方法是什么

请假设我无法重组表


谢谢

听起来您需要这样的结果集:

LoginTable
LoginID   Name    Time
100       Joe     12:00pm
101       Bob     3:30pm
102       Joe     4:00pm
103       Sue     6:15pm
MetricsTable
MetricID  LoginID   Label       Data
500       100       IPAddress   1.2.3.4
501       100       Attempts    25       
502       100       Status      Good
503       101       IPAddress   1.2.3.5
504       101       Attempts    19       
505       101       Status      Bad
506       102       IPAddress   1.2.3.6
507       102       Attempts    35       
508       102       Status      Hold
509       103       IPAddress   1.2.3.7
510       103       Attempts    4       
511       103       Status      Trial
SELECT LoginTable.LoginID, LoginTable.Name, LoginTable.Time, 
(SELECT MetricsTable.Data FROM MetricsTable WHERE
 MetricsTable.LoginID=LoginTable.LoginID and 
 MetricsTable.Label="IPAddress") as IPAddressEx
FROM LoginTable
LoginID   Name    Time   IP  Attempts  Status FutureColumn1 FutureColumn2 ...
你可以,或者你的数据

Select  LoginID,
        Name,
        Time,
        [IPAddress],
        [Attempts],
        [Status]
From   (Select  LoginTable.LoginID, 
                LoginTable.Name, 
                LoginTable.Time, 
                MetricsTable.Data,
                MetricsTable.Label
        From    LoginTable
        Inner   Join MetricsTable
                ON  MetricsTable.LoginID=LoginTable.LoginID) As nested
Pivot  (Min(Data) For Label In ([IPAddress],[Attempts],[Status])) As PivotTable

我没有时间来测试这一点,而且我也不是最擅长使用即时数据透视的人,但我认为这是正确的。

与Andrew的答案类似,我将改为将MetricsTable命名为MetricsTable

SELECT LoginTable.LoginID
    ,LoginTable.Name
    ,LoginTable.Time
    ,IPAddress= IPAddress.Data
    ,Attempts = Attempts.Data
FROM LoginTable
    Left Join MetricsTable As IPAddress
    On IPAddress.LoginID=LoginTable.LoginID 
    And IPAddress.Label="IPAddress"
    Left Join MetricsTable As Attempts
    On Attempts.LoginID=LoginTable.LoginID 
    And Attempts.Label="Attempts"
    -- Other joins for additional stats
如果您知道某些信息(如IPAddress)始终可用,请使用
内部联接
而不是
左联接

您可以按照Love2Learn的建议查看数据,但如果可能,我更喜欢直接连接

此外,如果LoginID不是LoginTable上的主键,则其上的索引将提高读取速度

同样,如果您在MetricsTable.LoginID上没有索引,我强烈建议您这样做


通过上面的查询,MetricsTable上的一个有用索引将位于LoginID和Label上(按该顺序),并且可能包含数据,以便数据库引擎可以从索引中读取所有数据。您应该进行性能测试,看看索引的开销是否值得。

您没有提到索引。您是否有,在哪些列上,以及上次重建/重新组织它们的时间?统计数据是最新的吗?你能展示一下查询的解释计划吗?为什么你不能简单地连接两个表呢?我只是说查询速度非常慢,因为任何人都可以看到它,并意识到它将永远无法运行。所以实际上我的问题不是速度,而是如何写得更好。下面涉及PIVOT的答案是我需要的方向,我不知道PIVOT的动作。我问这个问题,因为我不是一个MS SQL专家,我的驾驶室是C,C++,MFC,.NET WiFrms,JavaScript…不管怎样,我不可能一直都知道所有的事情,这就是为什么…尽管有聪明的反对票。。。吼叫声尝试下面的建议,然后标出答案。