ฉันเป็นแฟนของกุญแจตัวแทน มีความเสี่ยงที่การค้นพบของฉันจะยืนยันลำเอียง
คำถามมากมายที่ฉันเห็นทั้งที่นี่และที่http://stackoverflow.comใช้คีย์ธรรมชาติแทนคีย์ตัวแทนโดยยึดตามIDENTITY()
ค่า
พื้นหลังของฉันในระบบคอมพิวเตอร์บอกให้ฉันดำเนินการเปรียบเทียบใด ๆ กับจำนวนเต็มจะเร็วกว่าการเปรียบเทียบสตริง
ความคิดเห็นนี้ทำให้ฉันถามความเชื่อของฉันดังนั้นฉันคิดว่าฉันจะสร้างระบบเพื่อตรวจสอบวิทยานิพนธ์ของฉันว่าจำนวนเต็มเร็วกว่าสตริงเพื่อใช้เป็นกุญแจใน SQL Server
เนื่องจากมีความแตกต่างที่สังเกตได้น้อยมากในชุดข้อมูลขนาดเล็กฉันจึงนึกถึงการตั้งค่าตารางสองตารางทันทีที่ตารางหลักมี 1,000,000 แถวและตารางรองมี 10 แถวสำหรับแต่ละแถวในตารางหลักรวม 10,000,000 แถวใน ตารางที่สอง ข้อสมมติฐานของการทดสอบของฉันคือการสร้างตารางสองชุดเช่นนี้ชุดหนึ่งใช้คีย์ธรรมชาติและอีกชุดหนึ่งใช้คีย์จำนวนเต็มและเรียกใช้การทดสอบกำหนดเวลากับคำถามง่ายๆเช่น:
SELECT *
FROM Table1
INNER JOIN Table2 ON Table1.Key = Table2.Key;
ต่อไปนี้เป็นรหัสที่ฉันสร้างเป็นเตียงทดสอบ:
USE Master;
IF (SELECT COUNT(database_id) FROM sys.databases d WHERE d.name = 'NaturalKeyTest') = 1
BEGIN
ALTER DATABASE NaturalKeyTest SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE NaturalKeyTest;
END
GO
CREATE DATABASE NaturalKeyTest
ON (NAME = 'NaturalKeyTest', FILENAME =
'C:\SQLServer\Data\NaturalKeyTest.mdf', SIZE=8GB, FILEGROWTH=1GB)
LOG ON (NAME='NaturalKeyTestLog', FILENAME =
'C:\SQLServer\Logs\NaturalKeyTest.mdf', SIZE=256MB, FILEGROWTH=128MB);
GO
ALTER DATABASE NaturalKeyTest SET RECOVERY SIMPLE;
GO
USE NaturalKeyTest;
GO
CREATE VIEW GetRand
AS
SELECT RAND() AS RandomNumber;
GO
CREATE FUNCTION RandomString
(
@StringLength INT
)
RETURNS NVARCHAR(max)
AS
BEGIN
DECLARE @cnt INT = 0
DECLARE @str NVARCHAR(MAX) = '';
DECLARE @RandomNum FLOAT = 0;
WHILE @cnt < @StringLength
BEGIN
SELECT @RandomNum = RandomNumber
FROM GetRand;
SET @str = @str + CAST(CHAR((@RandomNum * 64.) + 32) AS NVARCHAR(MAX));
SET @cnt = @cnt + 1;
END
RETURN @str;
END;
GO
CREATE TABLE NaturalTable1
(
NaturalTable1Key NVARCHAR(255) NOT NULL
CONSTRAINT PK_NaturalTable1 PRIMARY KEY CLUSTERED
, Table1TestData NVARCHAR(255) NOT NULL
);
CREATE TABLE NaturalTable2
(
NaturalTable2Key NVARCHAR(255) NOT NULL
CONSTRAINT PK_NaturalTable2 PRIMARY KEY CLUSTERED
, NaturalTable1Key NVARCHAR(255) NOT NULL
CONSTRAINT FK_NaturalTable2_NaturalTable1Key
FOREIGN KEY REFERENCES dbo.NaturalTable1 (NaturalTable1Key)
ON DELETE CASCADE ON UPDATE CASCADE
, Table2TestData NVARCHAR(255) NOT NULL
);
GO
/* insert 1,000,000 rows into NaturalTable1 */
INSERT INTO NaturalTable1 (NaturalTable1Key, Table1TestData)
VALUES (dbo.RandomString(25), dbo.RandomString(100));
GO 1000000
/* insert 10,000,000 rows into NaturalTable2 */
INSERT INTO NaturalTable2 (NaturalTable2Key, NaturalTable1Key, Table2TestData)
SELECT dbo.RandomString(25), T1.NaturalTable1Key, dbo.RandomString(100)
FROM NaturalTable1 T1
GO 10
CREATE TABLE IDTable1
(
IDTable1Key INT NOT NULL CONSTRAINT PK_IDTable1
PRIMARY KEY CLUSTERED IDENTITY(1,1)
, Table1TestData NVARCHAR(255) NOT NULL
CONSTRAINT DF_IDTable1_TestData DEFAULT dbo.RandomString(100)
);
CREATE TABLE IDTable2
(
IDTable2Key INT NOT NULL CONSTRAINT PK_IDTable2
PRIMARY KEY CLUSTERED IDENTITY(1,1)
, IDTable1Key INT NOT NULL
CONSTRAINT FK_IDTable2_IDTable1Key FOREIGN KEY
REFERENCES dbo.IDTable1 (IDTable1Key)
ON DELETE CASCADE ON UPDATE CASCADE
, Table2TestData NVARCHAR(255) NOT NULL
CONSTRAINT DF_IDTable2_TestData DEFAULT dbo.RandomString(100)
);
GO
INSERT INTO IDTable1 DEFAULT VALUES;
GO 1000000
INSERT INTO IDTable2 (IDTable1Key)
SELECT T1.IDTable1Key
FROM IDTable1 T1
GO 10
รหัสข้างต้นสร้างฐานข้อมูลและ 4 ตารางและเติมตารางด้วยข้อมูลพร้อมที่จะทดสอบ รหัสทดสอบที่ฉันใช้คือ:
USE NaturalKeyTest;
GO
DECLARE @loops INT = 0;
DECLARE @MaxLoops INT = 10;
DECLARE @Results TABLE (
FinishedAt DATETIME DEFAULT (GETDATE())
, KeyType NVARCHAR(255)
, ElapsedTime FLOAT
);
WHILE @loops < @MaxLoops
BEGIN
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;
DBCC FREESYSTEMCACHE ('ALL');
DBCC DROPCLEANBUFFERS;
WAITFOR DELAY '00:00:05';
DECLARE @start DATETIME = GETDATE();
DECLARE @end DATETIME;
DECLARE @count INT;
SELECT @count = COUNT(*)
FROM dbo.NaturalTable1 T1
INNER JOIN dbo.NaturalTable2 T2 ON T1.NaturalTable1Key = T2.NaturalTable1Key;
SET @end = GETDATE();
INSERT INTO @Results (KeyType, ElapsedTime)
SELECT 'Natural PK' AS KeyType, CAST((@end - @start) AS FLOAT) AS ElapsedTime;
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;
DBCC FREESYSTEMCACHE ('ALL');
DBCC DROPCLEANBUFFERS;
WAITFOR DELAY '00:00:05';
SET @start = GETDATE();
SELECT @count = COUNT(*)
FROM dbo.IDTable1 T1
INNER JOIN dbo.IDTable2 T2 ON T1.IDTable1Key = T2.IDTable1Key;
SET @end = GETDATE();
INSERT INTO @Results (KeyType, ElapsedTime)
SELECT 'IDENTITY() PK' AS KeyType, CAST((@end - @start) AS FLOAT) AS ElapsedTime;
SET @loops = @loops + 1;
END
SELECT KeyType, FORMAT(CAST(AVG(ElapsedTime) AS DATETIME), 'HH:mm:ss.fff') AS AvgTime
FROM @Results
GROUP BY KeyType;
นี่คือผลลัพธ์:
ฉันกำลังทำสิ่งผิดปกติที่นี่หรือปุ่ม INT เร็วกว่าแป้นธรรมชาติ 25 ตัวอักษร 3 เท่าหรือไม่