(巨大的)嵌套循环(内连接)的替代方案

时间:2014-08-18 23:38:08

标签: sql sql-server performance database-performance

请查看此SELECT语句:

SELECT
    b.player_id,
    COUNT(CASE WHEN a.team = m.team_win THEN 1 END),
    COUNT(CASE WHEN a.team <> m.team_win THEN 1 END)
FROM
    players a,
    players b,
JOIN
    matches m
    ON m.match_id = b.match_id
WHERE
    a.player_id <> b.player_id
    and a.team <> b.team
    and a.player_id = 100
GROUP BY
    b.player_id

完成后,语句应显示一个记录集,其列为:

  • b.player_id与之对抗的a.player_id
  • count击败a.player_id的匹配b.player_id
  • count a.player_idb.player_id击败的matches

不幸的是,这些表非常大。 players大约有160万行。 players约有1700万行,因此加入它们会带来一些挑战:

执行计划索引同时搜索表matchesnested loop (inner join),然后发出player_id,这是 1,176,730,000,000 估计行的步骤。

其他misc。信息:

tinyintteambitteam_winbitmatch_id

bigint primary key playersCREATE TABLE [dbo].[Matches]( [match_id] [bigint] NOT NULL, [match_seq_id] [bigint] NOT NULL, [team_win] [bit] NOT NULL, CONSTRAINT [PK_Matches] PRIMARY KEY CLUSTERED ( [match_id] ASC ) ON [PRIMARY] ) ON [PRIMARY]

上有外键约束

匹配表

CREATE TABLE [dbo].[Players] (
    [id]         [int] PRIMARY KEY IDENTITY NOT NULL,
    [match_id]   [bigint] NOT NULL,
    [account_id] [bigint] NOT NULL,
    [team]       [bit] NOT NULL,
    [player_id]  [tinyint] NOT NULL,
    /* column list has been truncated for brevity. */
    CONSTRAINT [PK_Players] PRIMARY KEY CLUSTERED (
        [id] ASC
    ) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Players] ADD CONSTRAINT [FK_Players_Matches] FOREIGN KEY([match_id])
REFERENCES [dbo].[Matches] ([match_id])

玩家表

{{1}}

2 个答案:

答案 0 :(得分:3)

您错过了players表的加入,因此您获得了笛卡尔积。试试这个:

SELECT
    b.player_id,
    COUNT(CASE WHEN a.team = m.team_win THEN 0 END),
    COUNT(CASE WHEN a.team <> m.team_win THEN 1 END)
FROM
    matches m
JOIN players a ON m.match_id = a.match_id
JOIN players b ON m.match_id = b.match_id
WHERE
    a.player_id <> b.player_id
    and a.team <> b.team
    and a.player_id = 100
GROUP BY
    b.player_id

答案 1 :(得分:1)

你似乎想知道:对于每个球员,当球员对阵100时,球员队赢了多少次,输了多少次。让我们先得到球队总结:

SELECT p.team,
       SUM(CASE WHEN p.team = m.team_win THEN 1 ELSE 0 END) as teamwins,
       SUM(CASE WHEN p.team <> m.team_win THEN 1 ELSE 0 END) as teamlosts
FROM players p JOIN
     matches m
     ON m.match_id = p.match_id
GROUP BY p.team
HAVING sum(case when p.player_id = 100 then 1 else 0 end) -- be sure player 100 played

接下来,您可以加入玩家以获取团队信息。

我现在停在这里因为我需要确保球队随着时间的推移保持稳定。