如何加快创建大表 AlphaNumeric 代码的 SQL 脚本
Posted
技术标签:
【中文标题】如何加快创建大表 AlphaNumeric 代码的 SQL 脚本【英文标题】:How to speed up SQL script which creates a large table of AlphaNumeric codes 【发布时间】:2017-08-15 12:20:47 【问题描述】:我有以下脚本,它生成 1.75 亿(!)个格式为“ABC-1234”的唯一字母数字代码,范围从 AAA-0000 到 ZZZ-9999。
在我专用的 MS SQL 2016 机器上按原样运行此脚本需要 20 小时。加快速度的最佳方法是什么?从脚本中可以看出,我的 SQL 技能有些欠缺!
有一个 Identity (int) 列、ID 和 CODE (nvarchar(20)) 本身的列。这两列构成主键:
CREATE TABLE [dbo].[ORDERED_CODES](
[ID] [int] NOT NULL,
[Code] [nvarchar](20) NOT NULL,
CONSTRAINT [PK_ORDERED_CODES] PRIMARY KEY CLUSTERED
(
[ID] ASC,
[Code] 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
脚本:
DECLARE @Alpha1 INT;
DECLARE @Alpha2 INT;
DECLARE @Alpha3 INT;
DECLARE @Num INT;
-- alpha elements 'ABC'
SET @Alpha1 = 65;
SET @Alpha2 = 65;
SET @Alpha3 = 65;
-- number element '9999'
SET @Num = 0;
-- temporary holders
DECLARE @FINALCODE Nvarchar(50);
DECLARE @CODE1 Nvarchar(50);
DECLARE @CODE2 Nvarchar(50);
DECLARE @CODE3 Nvarchar(50);
WHILE @Alpha1 < 91
BEGIN
SET @CODE1 = CHAR(@Alpha1)
WHILE @Alpha2 < 91
BEGIN
SET @CODE2 = @CODE1 + CHAR(@Alpha2)
SET @Alpha2 = @Alpha2 +1
WHILE @Alpha3 < 91
BEGIN
SET @CODE3 = @CODE2 + CHAR(@Alpha3)
SET @Alpha3 = @Alpha3 +1
WHILE @Num < 10000
BEGIN
SET @FINALCODE = RIGHT('0000'+ CAST(@Num as nvarchar(4)),4) + CHAR(45) + @CODE3
SET @Num = @Num +1
INSERT INTO ORDERED_CODES (CODE) VALUES (@FINALCODE)
END
SET @FINALCODE = null
SET @Num = 0
END
SET @Alpha3 = 65
END
SET @Alpha2 = 65
SET @Alpha1 = @Alpha1 +1
END;
感谢所有想法!
【问题讨论】:
感谢 Gordon、Dan 和 John 抽出宝贵时间提供帮助,对于同一主题,所有这些都是很好的答案,所以遗憾的是我不得不选择一个作为答案......所以在最好的 SO 传统中必须去戈登才能成为第一。不用说,我要阅读 CTE!最快的是 Dan 的,在我的服务器上用了将近 4 分钟——我想我现在需要尝试找出为什么我的胖服务器比你的台式机慢 5 倍!比20小时好多了,我非常感激。伙计们干杯! 【参考方案1】:我会这样做:
with alphas as (
select v.ch
from (values ('A'), ('B'), . . .
) v(ch)
),
digits as (
select v.ch
from values ('0'), ('1'), . . .
)
select (a1.ch + a2.ch + a3.ch + d1.ch + d2.ch + d3.ch + d4.ch) as code
from alphas a1 cross join
alphas a2 cross join
alphas a3 cross join
digits d1 cross join
digits d2 cross join
digits d3 cross join
digits d4;
. . .
用于您想要的有效字符。如果您愿意,可以使用 values
以外的其他方法生成值。
【讨论】:
【参考方案2】:我希望 CTE 查询比循环执行得更好:
WITH
alpha_values AS (
SELECT value FROM(VALUES
('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M')
,('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z'))
AS alpha_values(value)
)
,t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,number_values AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1 AS value FROM t10 AS a CROSS JOIN t10 AS b CROSS JOIN t10 AS c)
INSERT INTO dbo.ORDERED_CODES (Code)
SELECT
alpha_values1.value
+ alpha_values2.value
+ alpha_values3.value
+ '-'
+ RIGHT('000' + CAST(number_values.value AS varchar(4)), 4)
AS Code
FROM alpha_values AS alpha_values1
CROSS JOIN alpha_values AS alpha_values2
CROSS JOIN alpha_values AS alpha_values3
CROSS JOIN number_values
ORDER BY Code;
编辑 直到我发布后,我才看到 Gordon 的类似解决方案。上面的查询在我的桌面上运行了 35 秒。
【讨论】:
【参考方案3】:借助临时计数表。在 1 分 6.799 秒内(在我的笔记本电脑上)记录了 175,760,000 条记录。或者,没有 Order By
的 37.833 秒
;with cteC as (
Select Top 26 C=char(64+Row_Number() Over (Order By (Select NULL))) From master..spt_values n1
), cteN as (
Select Top 10000 N= right(concat('0000',Row_Number() Over (Order By (Select NULL))-1),4) From master..spt_values n1, master..spt_values n2
)
Insert Into Ordered_Codes (Code)
Select Code=Concat(A.C,B.C,C.C,'-',N.N)
From cteC A,cteC B,cteC C,cteN N
Order By 1
cteC 生成 A - Z
cteN 生成 0000 - 99999
最终结果看起来像
【讨论】:
以上是关于如何加快创建大表 AlphaNumeric 代码的 SQL 脚本的主要内容,如果未能解决你的问题,请参考以下文章