Azure上のSQL Serverデータベース(Sql Server 2014/12.0.2000.8)
私は、すべて同じ基本的な選択プロパティと結合を持つストアドプロシージャを多数持っているため、すべてを網羅するビューを生成することにしました。次に、個々のストアドプロシージャで、追加のフィルタリングを行います。
ビューの実行プランに2つの異なるハッシュ一致(内部結合)部分が表示され、クエリが遅くなっていることに今日気づきました。実行計画から、最適化、または追加できる可能性のあるインデックスを特定するために、どの列または結合を確認する必要があるかを判断できません。
リンクされているのは、問題の実行プランです。 https://drive.google.com/file/d/1VeVrfD_usowEiPEn0KuVmREHl1CWCtxx/view?usp=sharing
Execプランを見ると、「ハッシュキープローブ」と「プローブ残差」セクションが記載されているため、プローブセクションの2つの列を使用して別のインデックスを追加しようとしましたが、うまくいきませんでした。これらのテーブルには既に大量のインデックスが作成されているため、困っています。
実行計画に沿ったクエリは次のとおりです。
select s.Division,
wr.Season,
wr.WeekNumber,
wr.RankingDate,
wr.IsCurrent,
wr.WeightClass,
wr.[Rank],
wr.WrestlerId,
w.LastName,
w.FirstName,
s.SchoolId,
s.[Name] [SchoolName],
coalesce(tr.DualRank, tr.TournamentRank, tr.[Rank]) [SchoolRank],
s.Conference,
s.ConferenceSeo,
dbo.uf_GetEligibilityString(r.WrestlerId, r.Season) [EligibilityYear],
w.HasRedshirted,
r.Starter,
r.IsRedshirting,
r.IsInjured,
dbo.uf_GetRecordString(st.Wins, st.Losses) [Record],
dbo.uf_GetRecordString(st.ConfWins, st.ConfLosses) [ConferenceRecord],
dbo.uf_GetPercentageString(st.Wins, (st.Wins + st.Losses)) [WinPercentage],
dbo.uf_GetPercentageString(st.MajorsFor + st.TechFall4For + st.TechFall5For + st.FallsFor, st.Wins) [BonusPercentage],
st.Wins,
st.Losses,
wr.EloRank [EloPoints],
0 [Trend],
999 [PreviousWeek]
from dbo.WrestlerRanking wr
join dbo.Wrestler w on w.WrestlerId = wr.WrestlerId
join dbo.Roster r on r.Season = wr.Season
and r.WrestlerId = wr.WrestlerId
join dbo.[Stats] st on st.Season = wr.Season
and st.WrestlerId = wr.WrestlerId
join dbo.School s on s.SchoolId = r.SchoolId
join dbo.TeamRankings tr on tr.Season = wr.Season
and tr.WeekNumber = wr.WeekNumber
and tr.SchoolId = s.SchoolId
where wr.[Rank] is not null
-- above here is the view, below here are the additional filters/where clauses added by the calling stored procedure
and s.Division = 'Division I'
and wr.Season = 2019
and r.Starter = 1
テーブルの定義は次のとおりです。
レスラーランキング
CREATE TABLE [dbo].[WrestlerRanking](
[WrestlerRankingId] [int] IDENTITY(1,1) NOT NULL,
[WrestlerId] [int] NOT NULL,
[Season] [int] NOT NULL,
[WeekNumber] [int] NOT NULL,
[Rank] [int] NULL,
[EloRank] [decimal](7, 2) NOT NULL,
[RankingDate] [datetime] NOT NULL,
[IsCurrent] [bit] NOT NULL,
[WeightClass] [int] NOT NULL,
[TournamentPoints] [decimal](3, 1) NOT NULL,
[TournamentBonus] [decimal](4, 2) NOT NULL,
[Division] [varchar](12) NOT NULL,
[StarterRank] [int] NULL,
CONSTRAINT [pk_WrestlerRanking_Season_WrestlerId_WeekNumber] PRIMARY KEY CLUSTERED
(
[Season] ASC,
[WrestlerId] ASC,
[WeekNumber] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
GO
ALTER TABLE [dbo].[WrestlerRanking] ADD DEFAULT ((0.0)) FOR [TournamentPoints]
GO
ALTER TABLE [dbo].[WrestlerRanking] ADD DEFAULT ((0.00)) FOR [TournamentBonus]
GO
ALTER TABLE [dbo].[WrestlerRanking] ADD DEFAULT ('Division I') FOR [Division]
GO
ALTER TABLE [dbo].[WrestlerRanking] WITH NOCHECK ADD CONSTRAINT [fk_WrestlerRanking_Wrestler] FOREIGN KEY([WrestlerId])
REFERENCES [dbo].[Wrestler] ([WrestlerId])
GO
ALTER TABLE [dbo].[WrestlerRanking] CHECK CONSTRAINT [fk_WrestlerRanking_Wrestler]
GO
レスラー:
CREATE TABLE [dbo].[Wrestler](
[WrestlerId] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](100) NOT NULL,
[FirstName] [varchar](100) NOT NULL,
[Aka] [varchar](100) NULL,
[UpdatedBy] [varchar](50) NULL,
[UpdatedDate] [datetime] NULL,
[HasRedshirted] [bit] NOT NULL,
[TwitterHandle] [varchar](56) NULL,
[CreatedBy] [varchar](50) NOT NULL,
[CreatedDate] [datetime] NULL,
[IsForfeit] [bit] NOT NULL,
CONSTRAINT [PK_Wrestler] PRIMARY KEY CLUSTERED
(
[WrestlerId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
GO
ALTER TABLE [dbo].[Wrestler] ADD DEFAULT ((1)) FOR [HasRedshirted]
GO
ALTER TABLE [dbo].[Wrestler] ADD DEFAULT ('service') FOR [CreatedBy]
GO
ALTER TABLE [dbo].[Wrestler] ADD DEFAULT (getutcdate()) FOR [CreatedDate]
GO
ALTER TABLE [dbo].[Wrestler] ADD DEFAULT ((0)) FOR [IsForfeit]
GO
名簿:
CREATE TABLE [dbo].[Roster](
[RosterId] [int] IDENTITY(1,1) NOT NULL,
[Season] [int] NOT NULL,
[SchoolId] [int] NOT NULL,
[WrestlerId] [int] NOT NULL,
[IsRedshirting] [bit] NOT NULL,
[EligibilityYear] [varchar](2) NOT NULL,
[WeightClass] [int] NOT NULL,
[Starter] [bit] NOT NULL,
[CreatedBy] [varchar](50) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedBy] [varchar](50) NULL,
[UpdatedDate] [datetime] NULL,
[IsInjured] [bit] NOT NULL,
[NationalParticipant] [bit] NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[RosterId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF),
CONSTRAINT [unique_Wrestler_Season] UNIQUE NONCLUSTERED
(
[Season] ASC,
[WrestlerId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT ((0)) FOR [IsRedshirting]
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT ('UN') FOR [EligibilityYear]
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT ((0)) FOR [WeightClass]
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT ((0)) FOR [Starter]
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT ('service') FOR [CreatedBy]
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT (getutcdate()) FOR [CreatedDate]
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT ((0)) FOR [IsInjured]
GO
ALTER TABLE [dbo].[Roster] ADD DEFAULT ((0)) FOR [NationalParticipant]
GO
ALTER TABLE [dbo].[Roster] WITH NOCHECK ADD CONSTRAINT [fk_Roster_School] FOREIGN KEY([SchoolId])
REFERENCES [dbo].[School] ([SchoolId])
GO
ALTER TABLE [dbo].[Roster] CHECK CONSTRAINT [fk_Roster_School]
GO
ALTER TABLE [dbo].[Roster] WITH NOCHECK ADD CONSTRAINT [fk_Roster_Wrestler] FOREIGN KEY([WrestlerId])
REFERENCES [dbo].[Wrestler] ([WrestlerId])
GO
ALTER TABLE [dbo].[Roster] CHECK CONSTRAINT [fk_Roster_Wrestler]
GO
統計:
CREATE TABLE [dbo].[Stats](
[StatsId] [int] IDENTITY(1,1) NOT NULL,
[WrestlerId] [int] NOT NULL,
[Wins] [int] NOT NULL,
[Losses] [int] NOT NULL,
[MajorsFor] [int] NOT NULL,
[MajorsAgainst] [int] NOT NULL,
[TechFall4For] [int] NOT NULL,
[TechFall4Against] [int] NOT NULL,
[TechFall5For] [int] NOT NULL,
[TechFall5Against] [int] NOT NULL,
[FallsFor] [int] NOT NULL,
[FallsAgainst] [int] NOT NULL,
[OtherWins] [int] NOT NULL,
[OtherLosses] [int] NOT NULL,
[AvgPointsFor] [decimal](4, 2) NULL,
[AvgPointsAgainst] [decimal](4, 2) NULL,
[BonusPercentage] [decimal](7, 4) NULL,
[WinsRank] [int] NULL,
[MDsRank] [int] NULL,
[T4sRank] [int] NULL,
[T5sRank] [int] NULL,
[FallsRank] [int] NULL,
[BonusPctRank] [int] NULL,
[AvgPointsForRank] [int] NULL,
[AvgPointsAgainstRank] [int] NULL,
[ConfWins] [int] NULL,
[ConfLosses] [int] NULL,
[ConfMajorsFor] [int] NULL,
[ConfMajorsAgainst] [int] NULL,
[ConfT4For] [int] NULL,
[ConfT4Against] [int] NULL,
[ConfT5For] [int] NULL,
[ConfT5Against] [int] NULL,
[ConfFallsFor] [int] NULL,
[ConfFallsAgainst] [int] NULL,
[ConfOtherWins] [int] NULL,
[ConfOtherLosses] [int] NULL,
[ConfAvgPointsFor] [decimal](4, 2) NULL,
[ConfAvgPointsAgainst] [decimal](4, 2) NULL,
[ConfBonusPercentage] [decimal](7, 4) NULL,
[ConfWinsRank] [int] NULL,
[ConfMDsRank] [int] NULL,
[ConfT4sRank] [int] NULL,
[ConfT5sRank] [int] NULL,
[ConfFallsRank] [int] NULL,
[ConfBonusPctRank] [int] NULL,
[ConfAvgPointsForRank] [int] NULL,
[ConfAvgPointsAgainstRank] [int] NULL,
[Season] [int] NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[StatsId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF),
CONSTRAINT [unique_Season_Wrestler] UNIQUE NONCLUSTERED
(
[Season] ASC,
[WrestlerId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [Wins]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [Losses]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [MajorsFor]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [MajorsAgainst]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [TechFall4For]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [TechFall4Against]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [TechFall5For]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [TechFall5Against]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [FallsFor]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [FallsAgainst]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [OtherWins]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((0)) FOR [OtherLosses]
GO
ALTER TABLE [dbo].[Stats] ADD DEFAULT ((2015)) FOR [Season]
GO
ALTER TABLE [dbo].[Stats] WITH NOCHECK ADD CONSTRAINT [FK_Statistics_Wrestler] FOREIGN KEY([WrestlerId])
REFERENCES [dbo].[Wrestler] ([WrestlerId])
GO
ALTER TABLE [dbo].[Stats] CHECK CONSTRAINT [FK_Statistics_Wrestler]
GO
学校:
CREATE TABLE [dbo].[School](
[SchoolId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NOT NULL,
[Division] [varchar](100) NULL,
[Conference] [varchar](100) NULL,
[Nickname] [varchar](100) NULL,
[Aka] [varchar](100) NULL,
[IsActive] [bit] NOT NULL,
[TwitterHandle] [varchar](56) NULL,
[CreatedBy] [varchar](100) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedBy] [varchar](100) NULL,
[UpdatedDate] [datetime] NULL,
[ConferenceSeo] [varchar](20) NULL,
[ShopUrl] [varchar](2000) NULL,
PRIMARY KEY CLUSTERED
(
[SchoolId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
GO
ALTER TABLE [dbo].[School] ADD DEFAULT ((1)) FOR [IsActive]
GO
ALTER TABLE [dbo].[School] ADD DEFAULT (suser_sname()) FOR [CreatedBy]
GO
ALTER TABLE [dbo].[School] ADD DEFAULT (getutcdate()) FOR [CreatedDate]
GO
TeamRankings:
CREATE TABLE [dbo].[TeamRankings](
[TeamRankingsId] [int] IDENTITY(1,1) NOT NULL,
[Points] [decimal](7, 2) NOT NULL,
[Rank] [int] NULL,
[SchoolId] [int] NOT NULL,
[Season] [int] NOT NULL,
[WeekNumber] [int] NOT NULL,
[IsCurrent] [bit] NOT NULL,
[RankingDate] [datetime] NOT NULL,
[TournamentPoints] [decimal](5, 2) NOT NULL,
[TournamentRank] [int] NOT NULL,
[DualWins] [int] NULL,
[DualLosses] [int] NULL,
[DualRank] [int] NULL,
[Division] [varchar](12) NOT NULL,
CONSTRAINT [pk_TeamRankings_Season_SchoolId_WeekNumber] PRIMARY KEY CLUSTERED
(
[Season] ASC,
[SchoolId] ASC,
[WeekNumber] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ((2014)) FOR [Season]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ((0)) FOR [WeekNumber]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ((0)) FOR [IsCurrent]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ('1900-01-01') FOR [RankingDate]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ((0)) FOR [TournamentPoints]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ((999)) FOR [TournamentRank]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ((0)) FOR [DualWins]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ((0)) FOR [DualLosses]
GO
ALTER TABLE [dbo].[TeamRankings] ADD DEFAULT ('Division I') FOR [Division]
GO
ALTER TABLE [dbo].[TeamRankings] WITH NOCHECK ADD CONSTRAINT [fk_TeamRankings_School] FOREIGN KEY([SchoolId])
REFERENCES [dbo].[School] ([SchoolId])
GO
ALTER TABLE [dbo].[TeamRankings] CHECK CONSTRAINT [fk_TeamRankings_School]
GO
実際のクエリプランでは、ほとんどの演算子を調べて、各演算子が使用するCPUと経過時間の概算を取得できます。これは、クエリプランの中で最も時間がかかった部分を特定するのに役立ちます。行モードのプランの場合、表示される数値はサブツリー全体の合計です。つまり、両方のハッシュ一致で使用されるCPUは13ミリ秒未満です。
クエリは合計192ミリ秒のCPUを使用します。クエリのパフォーマンスを調整する必要がある場合は、クエリ内のユーザー定義関数に焦点を当てます。実際の計画では、実行時間の約80%がこれらの関数に費やされていることが示されています。それらを最適化することは可能かもしれません。スカラUDFはパフォーマンスが大幅に低下する可能性があるため、最善の解決策はそれらを完全に削除することです。
元の質問に戻り、別のプランでパフォーマンスがどのように見えるかを確認したい場合は、次のキー列でインデックスを作成することをお勧めします:Season, WrestlerId, WeekNumber
。インデックスがカバーするように、含まれる列も追加する必要があります。理想的には、1つのインデックスに、クエリに必要なすべてのキーとインデックス付きの列が必要です。一部のキー列を含む別のインデックスを追加することは、このクエリに最適なアプローチではない場合があります。
idx_NC_WrestlerRanking_Season_WeekNumber_Division
インデックスはすでにカバーしているので、単にそのインデックスを変更することが可能かもしれません。インデックスの定義は質問に含まれていないため、詳細を述べるのは困難です。