SqlServer 수직 분할 테이블(프로그램 변경 최소화)

sql 서버의 디자인 특수성 때문에 일반적으로 대량의 데이터는 수평 테이블을 사용하지만 수직 테이블은 텍스트, 그림이 모두 큰 데이터를 단독 테이블에 넣는다. 이렇게 하면 데이터 디자인이 더욱 합리적일 수 있다. mysql보다 조금 나을 수 있다. mssql은 원래 하나의 파일이기 때문에 기본적으로 향상이 크지 않다. 현재로서는 수십만 개의 데이터가 테이블을 가리지 않고 아무런 영향을 미치지 않는다.천만 이상의 데이터에 대해서는 수평분표를 채택하는 것이 좋다.
수직 분표는 데이터베이스 디자인의 문제일 수 있기 때문에 상대적으로 보기 드물고 사용된다.만약에 데이터베이스에 있는 테이블의 일부 필드가 거의 변하지 않지만 자주 조회하고 일부 필드의 데이터가 빈번하게 변경된다면 이런 디자인은 같은 테이블에 넣는 것이 불합리하고 서로 영향이 너무 크다.변경된 테이블이 있을 때 열에 따라 테이블, 즉 수직으로 분할하는 것을 고려할 수 있다.
수직으로 시계를 나누는 사례가 비교적 적기 때문에 최근에 이런 시계가 존재하기 때문에 개인적으로 부추겼다.
소스 테이블 설계 구조:

--   
CREATE TABLE [dbo].[DemoTab](
[Guid] [uniqueidentifier] NOT NULL,
[UserName] [nvarchar](30) NOT NULL,
[Password] [nvarchar](30) NOT NULL,
[UserAccount] [varchar](30) NOT NULL,
[Amount] [numeric](18, 4) NULL,
CONSTRAINT [PK_DemoTab] PRIMARY KEY CLUSTERED ([Guid])
)
GO
 
 
ALTER TABLE [dbo].[DemoTab] 
ADD CONSTRAINT [DF_DemoTab_Guid] DEFAULT (newsequentialid()) FOR [Guid]
GO
 
--   ( )
CREATE VIEW [dbo].[VDemoTab]
AS
SELECT [Guid],[UserName],[Password],[UserAccount],[Amount]
FROM [dbo].[DemoTab]
GO
주: 분할 후 각 표의 메인 키는 모두 같고 분할 후의 표는 규범화되었다.
지금 시계 두 장으로 뜯어주세요.
시계를 기표로 선택하는 것을 주의하십시오. 다른 시계는 모두 이 시계와 키를 가지고 있습니다.

--   【1】, " ", " "
CREATE TABLE [dbo].[DemoTab001](
[Guid] [uniqueidentifier] NOT NULL,
[UserName] [nvarchar](30) NOT NULL,
[Password] [nvarchar](30) NOT NULL,
CONSTRAINT [PK_DemoTab001] PRIMARY KEY CLUSTERED ([Guid])
)
GO
 
--   , 
--ALTER TABLE [dbo].[DemoTab001] 
--ADD CONSTRAINT [DF_DemoTab001_Guid] DEFAULT (newsequentialid()) FOR [Guid]
--GO
 
--   【2】," "
CREATE TABLE [dbo].[DemoTab002](
[Guid] [uniqueidentifier] NOT NULL,
[UserAccount] [varchar](30) NOT NULL,
[Amount] [numeric](18, 4) NULL,
CONSTRAINT [PK_DemoTab002] PRIMARY KEY CLUSTERED ([Guid])
)
GO
 
--   , 
--ALTER TABLE [dbo].[DemoTab002] 
--ADD CONSTRAINT [DF_DemoTab002_Guid] DEFAULT (newsequentialid()) FOR [Guid]
--GO
 
 
--   ( ,  ON UPDATE CASCADE)
ALTER TABLE [dbo].[DemoTab002] 
ADD CONSTRAINT [FK_DemoTab002_DemoTab001_Guid] FOREIGN KEY ([Guid]) 
REFERENCES [DemoTab001]([Guid]) ON UPDATE CASCADE ON DELETE CASCADE
GO
이전에 단일 테이블이나 보기에 대한 조작이었다면, 분할 후 논리적 층의 변경이 많을 수 있으며, 변경을 최소화하기 위해 연합 보기로 조작할 수 있다.어떻게 연결표를 개인 상황에 따라 정합니까?

--   (INNER JOIN  )
ALTER VIEW [dbo].[VDemoTab]
AS
SELECT T1.[Guid],T1.[UserName],T1.[Password],T2.[UserAccount],T2.[Amount]
FROM [dbo].[DemoTab001] T1 LEFT JOIN [dbo].[DemoTab002] T2 ON T1.[Guid]=T2.[Guid]
GO
이 때 문제가 왔습니다. 시계에 대해 DML 조작을 해야 합니다. insert, update, delete는 어떻게 해결합니까?메인 키가 여러 테이블에 분산되어 있고 같은 것을 요구하기 때문이다!
이때 트리거를 고려해서만 일치성을 확보할 수 있으며, 트리거는 보기에 정의되어 있으며, INSTEAD OF 유형의 트리거를 사용한다.
insert 트리거:
보기 [VDemoTab]의 [Guid]는 시계 삽입 시간값입니다. 트리거 삽입 중 가상 시계 [inserted]의 [Guid]가 유일하기 때문에 트리거에서 이 [Guid]를 여러 개의 시계에 동시에 삽입할 수 있습니다. 여러 개의 시계의 [Guid]가 동일하다는 것을 보장합니다!

--  insert  
CREATE TRIGGER [dbo].[tgr_VDemoTab_insert]
ON [dbo].[VDemoTab] 
INSTEAD OF INSERT
AS 
BEGIN
 INSERT INTO [dbo].[DemoTab001]([Guid],[UserName],[Password])
 SELECT [Guid],[UserName],[Password] FROM inserted;
 
 INSERT INTO [dbo].[DemoTab002]([Guid],[UserAccount],[Amount])
 SELECT [Guid],[UserAccount],[Amount] FROM inserted;
END
GO
업데이트 트리거:
마찬가지로 업데이트할 때 가상 테이블 deleted와 inserted가 관련되고 업데이트는 보기 [VDemoTab]에 대한 업데이트이기 때문에 가상 테이블 inserted는 모든 필드를 포함하기 때문에 트리거가 각각 여러 개의 테이블을 업데이트해야 한다.

--  update  
CREATE TRIGGER [dbo].[tgr_VDemoTab_update]  
ON [dbo].[VDemoTab]   
INSTEAD OF UPDATE  
AS
BEGIN
 UPDATE T1 SET 
 T1.[UserName] = T2.[UserName], 
 T1.[Password] = T2.[Password]
 FROM [dbo].[DemoTab001] AS T1, inserted AS T2 WHERE T1.[Guid] = T2.[Guid] 
 
 UPDATE T1 SET 
 T1.[UserAccount] = T2.[UserAccount], 
 T1.[Amount] = T2.[Amount]
 FROM [dbo].[DemoTab002] AS T1, inserted AS T2 WHERE T1.[Guid] = T2.[Guid] 
END
GO
delete 트리거:
뷰 [VDemoTab] 레코드를 삭제하고 여러 테이블과 관련하여 삭제할 수 없으므로 마스터 테이블의 레코드만 삭제하면 다른 테이블은 종속 삭제됩니다.

--  delete  
CREATE TRIGGER [dbo].[tgr_VDemoTab_delete]  
ON [dbo].[VDemoTab]   
INSTEAD OF DELETE  
AS
BEGIN
    DELETE FROM [dbo].[DemoTab001]
    WHERE [Guid] IN (SELECT [Guid] FROM deleted)
END
GO
설계는 기본적으로 완성되었고, 지금 테스트를 진행한다.

INSERT INTO [dbo].[VDemoTab]([Guid],[UserName],[Password],[UserAccount],[Amount])
SELECT NEWID(),'user01','pw01','account01',100
UNION ALL
SELECT NEWID(),'user02','pw02','account02',99
UNION ALL
SELECT NEWID(),'user03','pw03','account03',0
GO
 
UPDATE [VDemoTab] SET [Password]='pw',[Amount]='10'
WHERE [Amount] >=0 AND [Amount]<100 AND [UserName] LIKE '%3'
GO
 
DELETE FROM [VDemoTab] WHERE [UserName] = 'user03'
GO
 
SELECT * FROM [dbo].[DemoTab001] 
SELECT * FROM [dbo].[DemoTab002] 
SELECT * FROM [dbo].[VDemoTab]
기본 조작은 모두 정상이다!수직 분표 완성!

성능은 어떻습니까?


Guid가 주 키로 사용되기 때문에 NEWSEQUENTIALID() 대신 NEWID() 를 사용합니다. 레코드가 추가될 때 인덱스를 모아 많은 데이터를 다시 정렬할 수 있습니다.
표를 나누면 한 개의 데이터 페이지에 저장할 수 있는 데이터가 더 많지만 여러 개의 표로 나누면 데이터 페이지도 많아지고 Guid는 모든 표에 존재하기 때문에 데이터를 조회할 때 IO가 더 많아진다.
업데이트 데이터에 대해 트리거에서 두 개의 테이블이 동시에 업데이트되며, 그 중 한 개의 테이블을 업데이트해도 다른 테이블은 영향을 미친다.만약 시계를 나눈 후에 동시에 업데이트하지 않는다면 트리거에서if(update(col))를 사용하여 업데이트가 그 열이라고 판단하면 해당하는 기본 시계를 업데이트하면 되고 다른 시계는 업데이트하지 않습니다.
가장 좋은 상황은 분할된 표는 모두'독립적'이다. 연합 보기를 사용하지 않고 조회와 변경이 독립적이기 때문에 논리층을 변경해야 한다.
이 SqlServer 수직분표(프로그램 변경 감소)에 관한 글은 여기 소개되어 있습니다. 더 많은 SqlServer 수직분표 내용은 저희 이전의 글을 검색하거나 아래의 관련 글을 계속 훑어보십시오. 앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기