如何加快创建大表 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 脚本的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中生成 ALPHANUMERIC 优惠券代码? [复制]

加快大表SQL查询的方法

SQL Server - 加快大表的计数

在同一列中不存在某些 ID 的大表中选择数据。加快查询

如何优化mysql中的大表?

如何在 python 中加快这个图像蒙版创建过程?