Sql server 外键关系可能存在的性能问题
我们有一个Sql server 外键关系可能存在的性能问题,sql-server,sql-server-2008,foreign-keys,foreign-key-relationship,database-performance,Sql Server,Sql Server 2008,Foreign Keys,Foreign Key Relationship,Database Performance,我们有一个User表,其中GUIDakauniqueidentifier作为PK。数据库中几乎所有其他表都使用4FK引用与此表关联。当我看DB图表时,它看起来像一条100车道的高速公路从用户表中出来,因为CreatedBy,CreatedByProxy,UpdatedBy,UpdatedBy外键 我被带到这个项目是因为它已经过了初始阶段,并且已经投入生产,并且存在性能问题 我想知道,当用户列表开始增长时,这种DB模式是否会导致严重的成长问题。因此,我们将来会遇到更多的性能问题吗?或者,如果我们创
User
表,其中GUID
akauniqueidentifier
作为PK
。数据库中几乎所有其他表都使用4FK
引用与此表关联。当我看DB
图表时,它看起来像一条100车道的高速公路从用户表中出来,因为CreatedBy
,CreatedByProxy
,UpdatedBy
,UpdatedBy
外键
我被带到这个项目是因为它已经过了初始阶段,并且已经投入生产,并且存在性能问题
我想知道,当用户列表开始增长时,这种DB
模式是否会导致严重的成长问题。因此,我们将来会遇到更多的性能问题吗?或者,如果我们创建一个索引,保留外键会导致索引变得庞大吗。我只是不记得以前有一个网站有外键到这种程度,我担心将来的校对/修复。我只是想证明是否保留或删除外键,或者修改结构,以便
用户表:
CREATE TABLE [dbo].[aspnet_Users](
[ApplicationId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL, -- ***** Here is the PK
[UserName] [nvarchar](256) NOT NULL,
[LoweredUserName] [nvarchar](256) NOT NULL,
[MobileAlias] [nvarchar](16) NULL,
[IsAnonymous] [bit] NOT NULL,
[LastActivityDate] [datetime] NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Email](
[EmailId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NULL,
[InstitutionId] [int] NULL,
[EmailTypeId] [int] NOT NULL,
[EmailAddress] [varchar](254) NOT NULL,
[IsFlaggedImportant] [bit] NOT NULL,
[IsDistrictRecord] [bit] NOT NULL,
[IsActive] [bit] NOT NULL,
[Created] [datetime] NOT NULL,
[CreatedBy] [uniqueidentifier] NOT NULL, -- ***** FK 1
[Proxy] [uniqueidentifier] NULL, -- ***** FK 2
[Updated] [datetime] NULL,
[UpdatedBy] [uniqueidentifier] NULL, -- ***** FK 3
[UpdateProxy] [uniqueidentifier] NULL, -- ***** FK 4
CONSTRAINT [PK_Email] PRIMARY KEY CLUSTERED
(
[EmailId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsPrimary] DEFAULT ((0)) FOR [IsFlaggedImportant]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsDistrictRecord] DEFAULT ((0)) FOR [IsDistrictRecord]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsActive] DEFAULT ((0)) FOR [IsActive]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_Created] DEFAULT (getdate()) FOR [Created]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_CreatedByUser] FOREIGN KEY([CreatedBy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_CreatedByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_EmailType] FOREIGN KEY([EmailTypeId])
REFERENCES [dbo].[EmailType] ([EmailTypeId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_EmailType]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_Institution] FOREIGN KEY([InstitutionId])
REFERENCES [dbo].[Institution] ([InstitutionId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_Institution]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([PersonId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_Person]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_ProxyByUser] FOREIGN KEY([Proxy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_ProxyByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_ProxyUpdateByUser] FOREIGN KEY([UpdateProxy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_ProxyUpdateByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_UpdatedByUser] FOREIGN KEY([UpdatedBy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_UpdatedByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [CK_Email_Person_Or_Institution] CHECK (([PersonId] IS NOT NULL AND [InstitutionId] IS NULL OR [PersonId] IS NULL AND [InstitutionId] IS NOT NULL))
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [CK_Email_Person_Or_Institution]
GO
另一个引用用户的表:
CREATE TABLE [dbo].[aspnet_Users](
[ApplicationId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL, -- ***** Here is the PK
[UserName] [nvarchar](256) NOT NULL,
[LoweredUserName] [nvarchar](256) NOT NULL,
[MobileAlias] [nvarchar](16) NULL,
[IsAnonymous] [bit] NOT NULL,
[LastActivityDate] [datetime] NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Email](
[EmailId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NULL,
[InstitutionId] [int] NULL,
[EmailTypeId] [int] NOT NULL,
[EmailAddress] [varchar](254) NOT NULL,
[IsFlaggedImportant] [bit] NOT NULL,
[IsDistrictRecord] [bit] NOT NULL,
[IsActive] [bit] NOT NULL,
[Created] [datetime] NOT NULL,
[CreatedBy] [uniqueidentifier] NOT NULL, -- ***** FK 1
[Proxy] [uniqueidentifier] NULL, -- ***** FK 2
[Updated] [datetime] NULL,
[UpdatedBy] [uniqueidentifier] NULL, -- ***** FK 3
[UpdateProxy] [uniqueidentifier] NULL, -- ***** FK 4
CONSTRAINT [PK_Email] PRIMARY KEY CLUSTERED
(
[EmailId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsPrimary] DEFAULT ((0)) FOR [IsFlaggedImportant]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsDistrictRecord] DEFAULT ((0)) FOR [IsDistrictRecord]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsActive] DEFAULT ((0)) FOR [IsActive]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_Created] DEFAULT (getdate()) FOR [Created]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_CreatedByUser] FOREIGN KEY([CreatedBy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_CreatedByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_EmailType] FOREIGN KEY([EmailTypeId])
REFERENCES [dbo].[EmailType] ([EmailTypeId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_EmailType]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_Institution] FOREIGN KEY([InstitutionId])
REFERENCES [dbo].[Institution] ([InstitutionId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_Institution]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([PersonId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_Person]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_ProxyByUser] FOREIGN KEY([Proxy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_ProxyByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_ProxyUpdateByUser] FOREIGN KEY([UpdateProxy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_ProxyUpdateByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_UpdatedByUser] FOREIGN KEY([UpdatedBy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_UpdatedByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [CK_Email_Person_Or_Institution] CHECK (([PersonId] IS NOT NULL AND [InstitutionId] IS NULL OR [PersonId] IS NULL AND [InstitutionId] IS NOT NULL))
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [CK_Email_Person_Or_Institution]
GO
我被带到这个项目是因为它已经过了初始阶段
并且已经投入生产,并且存在性能问题
您没有说明这些性能问题是什么,因此我将仅限于外键
当我看DB图时,它看起来像一条100车道的高速公路
由于CreatedBy、CreatedByProxy、,
UpdatedBy,UpdatedBy代理外键
当我看到这样的列时,我必须询问它们是否包含关于业务实体的信息——在本例中是一个人的电子邮件地址——或者关于该实体所在行的信息
它们似乎包含有关该行的信息。(但我可能错了。)
如果它们确实包含关于行的信息,并且在大多数查询中不需要它们,则可以将它们移动到另一个表中。如果移动它们,则在将行插入dbo.Email时必须更加小心
CREATE TABLE [dbo].[Email](
[EmailId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NULL,
[InstitutionId] [int] NULL,
[EmailTypeId] [int] NOT NULL,
[EmailAddress] [varchar](254) NOT NULL,
[IsFlaggedImportant] [bit] NOT NULL,
[IsDistrictRecord] [bit] NOT NULL,
[IsActive] [bit] NOT NULL,
CONSTRAINT [PK_Email] PRIMARY KEY CLUSTERED ([EmailID])
);
CREATE TABLE [dbo].[Email_audit](
[EmailID] [int] PRIMARY KEY REFERENCES [Email] ([EmailID]),
[Created] [datetime] NOT NULL,
[CreatedBy] [uniqueidentifier] NOT NULL, -- ***** FK 1
[Proxy] [uniqueidentifier] NULL, -- ***** FK 2
[Updated] [datetime] NULL,
[UpdatedBy] [uniqueidentifier] NULL, -- ***** FK 3
[UpdateProxy] [uniqueidentifier] NULL -- ***** FK 4
);
这类表通常用于提供某种审计跟踪。是否可以级联删除取决于应用程序。在某些应用程序中,您需要在此处存储电子邮件地址而不是电子邮件id号,并且不使用外键引用。(这允许从dbo.Email中删除行,同时保留有关行发生了什么的一些信息。)
移动这些列可以将dbo.Email中的行宽度减少约80字节,而不计算开销。这通常会提高从中移动SELECT语句的表中SELECT语句的性能。(行数越窄;每页行数越多。)
但是,移动这些列会使插入和更新行变得复杂。所有的插入和更新都必须命中两个表。在GUID
列上使用集群主键肯定会破坏性能。这将导致大量索引碎片,并可能导致操作中出现大量页面拆分,从而导致最终性能损失,但OP没有在GUID上创建群集主键。OP在一个表中的GUID上有一个非聚集主键,在另一个表中的电子邮件上有一个聚集主键。