Làm cách nào tôi có thể chuyển đổi 100 triệu số nguyên dương đầu tiên thành chuỗi?


13

Đây là một chút của một sự chuyển hướng từ vấn đề thực sự. Nếu cung cấp ngữ cảnh giúp, việc tạo dữ liệu này có thể hữu ích cho các cách xử lý hiệu suất của chuỗi xử lý, để tạo chuỗi cần áp dụng một số thao tác cho chúng trong một con trỏ hoặc để tạo thay thế tên ẩn danh duy nhất cho dữ liệu nhạy cảm. Tôi chỉ quan tâm đến các cách tạo dữ liệu hiệu quả trong Máy chủ SQL, vui lòng không hỏi tại sao tôi cần tạo dữ liệu này.

Tôi sẽ cố gắng bắt đầu với một định nghĩa hơi chính thức. Một chuỗi được bao gồm trong chuỗi nếu nó chỉ bao gồm các chữ in hoa từ A - Z. Thuật ngữ đầu tiên của chuỗi là "A". Sê-ri bao gồm tất cả các chuỗi hợp lệ được sắp xếp theo độ dài thứ tự đầu tiên và thứ tự chữ cái điển hình thứ hai. Nếu các chuỗi nằm trong một bảng trong một cột được gọi STRING_COL, thứ tự có thể được xác định trong T-SQL là ORDER BY LEN(STRING_COL) ASC, STRING_COL ASC.

Để đưa ra một định nghĩa ít chính thức hơn, hãy xem các tiêu đề cột theo thứ tự chữ cái trong excel. Bộ này là cùng một mô hình. Xem xét cách bạn có thể chuyển đổi một số nguyên thành số 26 cơ sở:

1 -> A, 2 -> B, 3 -> C, ..., 25 -> Y, 26 -> Z, 27 -> AA, 28 -> AB, ...

Sự tương tự không hoàn hảo lắm vì "A" hành xử khác 0 trong cơ sở mười. Dưới đây là bảng các giá trị được chọn, hy vọng sẽ làm cho nó rõ ràng hơn:

╔════════════╦════════╗
 ROW_NUMBER  STRING 
╠════════════╬════════╣
          1  A      
          2  B      
         25  Y      
         26  Z      
         27  AA     
         28  AB     
         51  AY     
         52  AZ     
         53  BA     
         54  BB     
      18278  ZZZ    
      18279  AAAA   
     475253  ZZZY   
     475254  ZZZZ   
     475255  AAAAA  
  100000000  HJUNYV 
╚════════════╩════════╝

Mục tiêu là viết một SELECTtruy vấn trả về chuỗi 100000000 đầu tiên theo thứ tự được xác định ở trên. Tôi đã thực hiện thử nghiệm của mình bằng cách chạy các truy vấn trong SSMS với kết quả được loại bỏ trái ngược với việc lưu nó vào bảng:

loại bỏ tập kết quả

Lý tưởng nhất là truy vấn sẽ có hiệu quả hợp lý. Ở đây tôi đang xác định hiệu quả là thời gian cpu cho một truy vấn nối tiếp và thời gian trôi qua cho một truy vấn song song. Bạn có thể sử dụng bất kỳ thủ thuật không có giấy tờ nào mà bạn thích. Dựa vào hành vi không xác định hoặc không được bảo đảm là tốt, nhưng nó sẽ được đánh giá cao nếu bạn gọi nó trong câu trả lời của bạn.

Một số phương pháp tạo hiệu quả tập dữ liệu được mô tả ở trên là gì? Martin Smith đã chỉ ra rằng một thủ tục lưu trữ CLR có thể không phải là một cách tiếp cận tốt do chi phí xử lý quá nhiều hàng.

Câu trả lời:


7

Giải pháp của bạn chạy trong 35 giây trên máy tính xách tay của tôi. Các mã sau đây mất 26 giây (bao gồm tạo và điền vào các bảng tạm thời):

Bảng tạm thời

DROP TABLE IF EXISTS #T1, #T2, #T3, #T4;

CREATE TABLE #T1 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T2 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T3 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T4 (string varchar(6) NOT NULL PRIMARY KEY);

INSERT #T1 (string)
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');

INSERT #T2 (string)
SELECT T1a.string + T1b.string
FROM #T1 AS T1a, #T1 AS T1b;

INSERT #T3 (string)
SELECT #T2.string + #T1.string
FROM #T2, #T1;

INSERT #T4 (string)
SELECT #T3.string + #T1.string
FROM #T3, #T1;

Ý tưởng là để tập hợp trước các tổ hợp có tối đa bốn ký tự.

Mã chính

SELECT TOP (100000000)
    UA.string + UA.string2
FROM
(
    SELECT U.Size, U.string, string2 = '' FROM 
    (
        SELECT Size = 1, string FROM #T1
        UNION ALL
        SELECT Size = 2, string FROM #T2
        UNION ALL
        SELECT Size = 3, string FROM #T3
        UNION ALL
        SELECT Size = 4, string FROM #T4
    ) AS U
    UNION ALL
    SELECT Size = 5, #T1.string, string2 = #T4.string
    FROM #T1, #T4
    UNION ALL
    SELECT Size = 6, #T2.string, #T4.string
    FROM #T2, #T4
) AS UA
ORDER BY 
    UA.Size, 
    UA.string, 
    UA.string2
OPTION (NO_PERFORMANCE_SPOOL, MAXDOP 1);

Đó là một liên kết duy trì trật tự đơn giản * của bốn bảng được tính toán trước, với các chuỗi 5 ký tự và 6 ký tự xuất phát khi cần thiết. Tách tiền tố từ hậu tố tránh sắp xếp.

Kế hoạch thực hiện

100 triệu hàng


* Không có gì trong SQL ở trên chỉ định liên kết giữ trật tự trực tiếp. Trình tối ưu hóa chọn các toán tử vật lý với các thuộc tính khớp với đặc tả truy vấn SQL, bao gồm cả thứ tự cấp cao nhất theo. Ở đây, nó chọn phép nối được thực hiện bởi toán tử vật lý tham gia hợp nhất để tránh sắp xếp.

Đảm bảo là kế hoạch thực hiện cung cấp thứ tự ngữ nghĩa và cấp cao truy vấn theo đặc tả. Biết rằng hợp nhất tham gia concat giữ trật tự cho phép người viết truy vấn dự đoán một kế hoạch thực hiện, nhưng trình tối ưu hóa sẽ chỉ cung cấp nếu kỳ vọng là hợp lệ.


6

Tôi sẽ đăng câu trả lời để bắt đầu. Suy nghĩ đầu tiên của tôi là có thể tận dụng tính chất bảo toàn trật tự của một vòng lặp lồng nhau cùng với một vài bảng trợ giúp có một hàng cho mỗi chữ cái. Phần khó khăn sẽ được lặp theo cách mà các kết quả được sắp xếp theo chiều dài cũng như tránh trùng lặp. Ví dụ: khi tham gia chéo một CTE bao gồm tất cả 26 chữ in hoa cùng với '', bạn có thể kết thúc việc tạo 'A' + '' + 'A''' + 'A' + 'A'tất nhiên đó là cùng một chuỗi.

Quyết định đầu tiên là nơi lưu trữ dữ liệu của người trợ giúp. Tôi đã thử sử dụng bảng tạm thời nhưng điều này có tác động tiêu cực đáng ngạc nhiên đến hiệu suất, mặc dù dữ liệu phù hợp với một trang. Bảng tạm thời chứa dữ liệu dưới đây:

SELECT 'A'
UNION ALL SELECT 'B'
...
UNION ALL SELECT 'Y'
UNION ALL SELECT 'Z'

So với việc sử dụng CTE, truy vấn mất nhiều thời gian hơn 3 lần với bảng phân cụm và 4 lần dài hơn với một đống. Tôi không tin rằng vấn đề là dữ liệu trên đĩa. Nó nên được đọc vào bộ nhớ dưới dạng một trang duy nhất và được xử lý trong bộ nhớ cho toàn bộ kế hoạch. Có lẽ SQL Server có thể làm việc với dữ liệu từ toán tử Constant Scan hiệu quả hơn so với dữ liệu được lưu trữ trong các trang của hàng lưu trữ thông thường.

Thật thú vị, SQL Server chọn đặt các kết quả được đặt hàng từ một bảng tempdb trang duy nhất với dữ liệu được sắp xếp vào một bộ đệm bảng:

spoool xấu

SQL Server thường đặt kết quả cho bảng bên trong của phép nối chéo vào bộ đệm bảng, ngay cả khi nó có vẻ vô nghĩa khi làm như vậy. Tôi nghĩ rằng trình tối ưu hóa cần một chút công việc trong lĩnh vực này. Tôi chạy truy vấn với NO_PERFORMANCE_SPOOLđể tránh hiệu suất nhấn.

Một vấn đề với việc sử dụng CTE để lưu trữ dữ liệu của người trợ giúp là dữ liệu không được đảm bảo để được đặt hàng. Tôi không thể nghĩ tại sao trình tối ưu hóa lại chọn không đặt hàng và trong tất cả các thử nghiệm của tôi, dữ liệu đã được xử lý theo thứ tự tôi đã viết CTE:

thứ tự quét liên tục

Tuy nhiên, tốt nhất không nên nắm bắt bất kỳ cơ hội nào, đặc biệt là nếu có cách để làm điều đó mà không có chi phí hiệu suất lớn. Có thể sắp xếp dữ liệu trong một bảng dẫn xuất bằng cách thêm một TOPtoán tử thừa . Ví dụ:

(SELECT TOP (26) CHR FROM FIRST_CHAR ORDER BY CHR)

Việc thêm vào truy vấn sẽ đảm bảo rằng kết quả sẽ được trả về theo đúng thứ tự. Tôi dự kiến ​​tất cả các loại sẽ có tác động tiêu cực lớn. Trình tối ưu hóa truy vấn dự kiến ​​điều này cũng dựa trên chi phí ước tính:

loại đắt tiền

Rất ngạc nhiên, tôi không thể quan sát thấy bất kỳ sự khác biệt có ý nghĩa thống kê về thời gian hoặc thời gian chạy cpu có hoặc không có thứ tự rõ ràng. Nếu bất cứ điều gì, truy vấn dường như chạy nhanh hơn với ORDER BY! Tôi không có lời giải thích cho hành vi này.

Phần khó khăn của vấn đề là tìm ra cách chèn các ký tự trống vào đúng chỗ. Như đã đề cập trước một đơn giản CROSS JOINsẽ dẫn đến dữ liệu trùng lặp. Chúng tôi biết rằng chuỗi 100000000 sẽ có độ dài sáu ký tự vì:

26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 = 914654 <100000000

nhưng

26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 + 26 ^ 6 = 321272406> 100000000

Vì vậy, chúng tôi chỉ cần tham gia vào thư CTE sáu lần. Giả sử rằng chúng tôi tham gia CTE sáu lần, lấy một chữ cái từ mỗi CTE và ghép chúng lại với nhau. Giả sử chữ cái ngoài cùng bên trái không trống. Nếu bất kỳ chữ cái tiếp theo nào trống có nghĩa là chuỗi dài dưới sáu ký tự thì đó là một bản sao. Do đó, chúng ta có thể ngăn các bản sao bằng cách tìm ký tự không trống đầu tiên và yêu cầu tất cả các ký tự sau nó cũng không trống. Tôi đã chọn theo dõi điều này bằng cách chỉ định một FLAGcột cho một trong các CTE và bằng cách thêm một kiểm tra vào WHEREmệnh đề. Điều này sẽ rõ ràng hơn sau khi nhìn vào truy vấn. Truy vấn cuối cùng như sau:

WITH FIRST_CHAR (CHR) AS
(
    SELECT 'A'
    UNION ALL SELECT 'B'
    UNION ALL SELECT 'C'
    UNION ALL SELECT 'D'
    UNION ALL SELECT 'E'
    UNION ALL SELECT 'F'
    UNION ALL SELECT 'G'
    UNION ALL SELECT 'H'
    UNION ALL SELECT 'I'
    UNION ALL SELECT 'J'
    UNION ALL SELECT 'K'
    UNION ALL SELECT 'L'
    UNION ALL SELECT 'M'
    UNION ALL SELECT 'N'
    UNION ALL SELECT 'O'
    UNION ALL SELECT 'P'
    UNION ALL SELECT 'Q'
    UNION ALL SELECT 'R'
    UNION ALL SELECT 'S'
    UNION ALL SELECT 'T'
    UNION ALL SELECT 'U'
    UNION ALL SELECT 'V'
    UNION ALL SELECT 'W'
    UNION ALL SELECT 'X'
    UNION ALL SELECT 'Y'
    UNION ALL SELECT 'Z'
)
, ALL_CHAR (CHR, FLAG) AS
(
    SELECT '', 0 CHR
    UNION ALL SELECT 'A', 1
    UNION ALL SELECT 'B', 1
    UNION ALL SELECT 'C', 1
    UNION ALL SELECT 'D', 1
    UNION ALL SELECT 'E', 1
    UNION ALL SELECT 'F', 1
    UNION ALL SELECT 'G', 1
    UNION ALL SELECT 'H', 1
    UNION ALL SELECT 'I', 1
    UNION ALL SELECT 'J', 1
    UNION ALL SELECT 'K', 1
    UNION ALL SELECT 'L', 1
    UNION ALL SELECT 'M', 1
    UNION ALL SELECT 'N', 1
    UNION ALL SELECT 'O', 1
    UNION ALL SELECT 'P', 1
    UNION ALL SELECT 'Q', 1
    UNION ALL SELECT 'R', 1
    UNION ALL SELECT 'S', 1
    UNION ALL SELECT 'T', 1
    UNION ALL SELECT 'U', 1
    UNION ALL SELECT 'V', 1
    UNION ALL SELECT 'W', 1
    UNION ALL SELECT 'X', 1
    UNION ALL SELECT 'Y', 1
    UNION ALL SELECT 'Z', 1
)
SELECT TOP (100000000)
d6.CHR + d5.CHR + d4.CHR + d3.CHR + d2.CHR + d1.CHR
FROM (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d6
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d5
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d4
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d3
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d2
CROSS JOIN (SELECT TOP (26) CHR FROM FIRST_CHAR ORDER BY CHR) d1
WHERE (d2.FLAG + d3.FLAG + d4.FLAG + d5.FLAG + d6.FLAG) =
    CASE 
    WHEN d6.FLAG = 1 THEN 5
    WHEN d5.FLAG = 1 THEN 4
    WHEN d4.FLAG = 1 THEN 3
    WHEN d3.FLAG = 1 THEN 2
    WHEN d2.FLAG = 1 THEN 1
    ELSE 0 END
OPTION (MAXDOP 1, FORCE ORDER, LOOP JOIN, NO_PERFORMANCE_SPOOL);

Các CTE được mô tả ở trên. ALL_CHARđược nối đến năm lần vì nó bao gồm một hàng cho một ký tự trống. Ký tự cuối cùng trong chuỗi không bao giờ được để trống để CTE riêng được xác định cho nó , FIRST_CHAR. Cột cờ bổ sung trong ALL_CHARđược sử dụng để ngăn ngừa trùng lặp như mô tả ở trên. Có thể có một cách hiệu quả hơn để thực hiện kiểm tra này nhưng chắc chắn có nhiều cách không hiệu quả hơn để thực hiện. Một nỗ lực của tôi với LEN()POWER() làm cho truy vấn chạy chậm hơn sáu lần so với phiên bản hiện tại.

Các gợi ý MAXDOP 1FORCE ORDERgợi ý là rất cần thiết để đảm bảo rằng thứ tự được bảo toàn trong truy vấn. Một kế hoạch ước tính có chú thích có thể hữu ích để xem tại sao các liên kết theo thứ tự hiện tại của chúng:

chú thích ước tính

Các gói truy vấn thường được đọc từ phải sang trái nhưng các yêu cầu hàng xảy ra từ trái sang phải. Lý tưởng nhất là SQL Server sẽ yêu cầu chính xác 100 triệu hàng từ d1toán tử quét không đổi. Khi bạn di chuyển từ trái sang phải, tôi hy vọng sẽ có ít hàng được yêu cầu hơn từ mỗi toán tử. Chúng ta có thể thấy điều này trong kế hoạch thực hiện thực tế . Ngoài ra, bên dưới là ảnh chụp màn hình từ SQL Sentry Plan Explorer:

nhà thám hiểm

Chúng tôi có chính xác 100 triệu hàng từ d1, đó là một điều tốt. Lưu ý rằng tỷ lệ của các hàng giữa d2 và d3 gần như chính xác là 27: 1 (165336 * 27 = 4464072), điều này có ý nghĩa nếu bạn nghĩ về cách liên kết chéo sẽ hoạt động. Tỷ lệ của các hàng giữa d1 và d2 là 22,4 đại diện cho một số công việc lãng phí. Tôi tin rằng các hàng thừa là từ các bản sao (do các ký tự trống ở giữa các chuỗi) không vượt qua được toán tử nối vòng lặp lồng nhau thực hiện quá trình lọc.

Các LOOP JOINgợi ý là không cần thiết về mặt kỹ thuật vì một CROSS JOINchỉ có thể được thực hiện như một vòng tham gia trong SQL Server. Các NO_PERFORMANCE_SPOOLlà để ngăn chặn các spooling bảng không cần thiết. Việc bỏ qua gợi ý bộ đệm làm cho truy vấn mất 3 lần lâu hơn trên máy của tôi.

Truy vấn cuối cùng có thời gian cpu khoảng 17 giây và tổng thời gian trôi qua là 18 giây. Đó là khi chạy truy vấn thông qua SSMS và loại bỏ tập kết quả. Tôi rất thích thú khi thấy các phương pháp tạo dữ liệu khác.


2

Tôi có một giải pháp được tối ưu hóa để có được mã chuỗi cho bất kỳ số cụ thể nào lên tới 217.180.147.158 (8 ký tự). Nhưng tôi không thể đánh bại thời gian của bạn:

Trên máy của tôi, với SQL Server 2014, truy vấn của bạn mất 18 giây, trong khi truy vấn của tôi mất 3 giây 46 giây. Cả hai truy vấn đều sử dụng cờ theo dõi không có giấy tờ 8690 vì năm 2014 không hỗ trợ NO_PERFORMANCE_SPOOLgợi ý.

Đây là mã:

/* precompute offsets and powers to simplify final query */
CREATE TABLE #ExponentsLookup (
    offset          BIGINT NOT NULL,
    offset_end      BIGINT NOT NULL,
    position        INTEGER NOT NULL,
    divisor         BIGINT NOT NULL,
    shifts          BIGINT NOT NULL,
    chars           INTEGER NOT NULL,
    PRIMARY KEY(offset, offset_end, position)
);

WITH base_26_multiples AS ( 
    SELECT  number  AS exponent,
            CAST(POWER(26.0, number) AS BIGINT) AS multiple
    FROM    master.dbo.spt_values
    WHERE   [type] = 'P'
            AND number < 8
),
num_offsets AS (
    SELECT  *,
            -- The maximum posible value is 217180147159 - 1
            LEAD(offset, 1, 217180147159) OVER(
                ORDER BY exponent
            ) AS offset_end
    FROM    (
                SELECT  exponent,
                        SUM(multiple) OVER(
                            ORDER BY exponent
                        ) AS offset
                FROM    base_26_multiples
            ) x
)
INSERT INTO #ExponentsLookup(offset, offset_end, position, divisor, shifts, chars)
SELECT  ofst.offset, ofst.offset_end,
        dgt.number AS position,
        CAST(POWER(26.0, dgt.number) AS BIGINT)     AS divisor,
        CAST(POWER(256.0, dgt.number) AS BIGINT)    AS shifts,
        ofst.exponent + 1                           AS chars
FROM    num_offsets ofst
        LEFT JOIN master.dbo.spt_values dgt --> as many rows as resulting chars in string
            ON [type] = 'P'
            AND dgt.number <= ofst.exponent;

/*  Test the cases in table example */
SELECT  /*  1.- Get the base 26 digit and then shift it to align it to 8 bit boundaries
            2.- Sum the resulting values
            3.- Bias the value with a reference that represent the string 'AAAAAAAA'
            4.- Take the required chars */
        ref.[row_number],
        REVERSE(SUBSTRING(REVERSE(CAST(SUM((((ref.[row_number] - ofst.offset) / ofst.divisor) % 26) * ofst.shifts) +
            CAST(CAST('AAAAAAAA' AS BINARY(8)) AS BIGINT) AS BINARY(8))),
            1, MAX(ofst.chars))) AS string
FROM    (
            VALUES(1),(2),(25),(26),(27),(28),(51),(52),(53),(54),
            (18278),(18279),(475253),(475254),(475255),
            (100000000), (CAST(217180147158 AS BIGINT))
        ) ref([row_number])
        LEFT JOIN #ExponentsLookup ofst
            ON ofst.offset <= ref.[row_number]
            AND ofst.offset_end > ref.[row_number]
GROUP BY
        ref.[row_number]
ORDER BY
        ref.[row_number];

/*  Test with huge set  */
WITH numbers AS (
    SELECT  TOP(100000000)
            ROW_NUMBER() OVER(
                ORDER BY x1.number
            ) AS [row_number]
    FROM    master.dbo.spt_values x1
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 676) x2
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 676) x3
    WHERE   x1.number < 219
)
SELECT  /*  1.- Get the base 26 digit and then shift it to align it to 8 bit boundaries
            2.- Sum the resulting values
            3.- Bias the value with a reference that represent the string 'AAAAAAAA'
            4.- Take the required chars */
        ref.[row_number],
        REVERSE(SUBSTRING(REVERSE(CAST(SUM((((ref.[row_number] - ofst.offset) / ofst.divisor) % 26) * ofst.shifts) +
            CAST(CAST('AAAAAAAA' AS BINARY(8)) AS BIGINT) AS BINARY(8))),
            1, MAX(ofst.chars))) AS string
FROM    numbers ref
        LEFT JOIN #ExponentsLookup ofst
            ON ofst.offset <= ref.[row_number]
            AND ofst.offset_end > ref.[row_number]
GROUP BY
        ref.[row_number]
ORDER BY
        ref.[row_number]
OPTION (QUERYTRACEON 8690);

Mẹo ở đây là tính toán trước khi các hoán vị khác nhau bắt đầu:

  1. Khi bạn phải xuất một char duy nhất, bạn có 26 ^ 1 hoán vị bắt đầu từ 26 ^ 0.
  2. Khi bạn phải xuất 2 ký tự, bạn có 26 ^ 2 hoán vị bắt đầu từ 26 ^ 0 + 26 ^ 1
  3. Khi bạn phải xuất 3 ký tự, bạn có 26 ^ 3 hoán vị bắt đầu từ 26 ^ 0 + 26 ^ 1 + 26 ^ 2
  4. lặp lại cho n ký tự

Thủ thuật khác được sử dụng là chỉ đơn giản là sử dụng tổng để có được giá trị phù hợp thay vì cố gắng nối. Để đạt được điều này, tôi chỉ cần bù các chữ số từ cơ sở 26 đến cơ sở 256 và thêm giá trị ascii của 'A' cho mỗi chữ số. Vì vậy, chúng tôi có được biểu diễn nhị phân của chuỗi chúng tôi đang tìm kiếm. Sau đó, một số thao tác chuỗi hoàn thành quá trình.


-1

ok, đây là kịch bản mới nhất của tôi.

Không lặp, không đệ quy.

Nó chỉ hoạt động cho 6 char

Hạn chế lớn nhất là mất khoảng 22 phút với giá 1,00,00,000

Lần này kịch bản của tôi rất ngắn.

SET NoCount on

declare @z int=26
declare @start int=@z+1 
declare @MaxLimit int=10000000

SELECT TOP (@MaxLimit) IDENTITY(int,1,1) AS N
    INTO NumbersTest1
    FROM     master.dbo.spt_values x1   
   CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 500) x2
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 500) x3
    WHERE   x1.number < 219
ALTER TABLE NumbersTest1 ADD CONSTRAINT PK_NumbersTest1 PRIMARY KEY CLUSTERED (N)


select N, strCol from NumbersTest1
cross apply
(
select 
case when IntCol6>0 then  char((IntCol6%@z)+64) else '' end 
+case when IntCol5=0 then 'Z' else isnull(char(IntCol5+64),'') end 
+case when IntCol4=0 then 'Z' else isnull(char(IntCol4+64),'') end 
+case when IntCol3=0 then 'Z' else isnull(char(IntCol3+64),'') end 
+case when IntCol2=0 then 'Z' else isnull(char(IntCol2+64),'') end 
+case when IntCol1=0 then 'Z' else isnull(char(IntCol1+64),'') end strCol
from
(
select  IntCol1,IntCol2,IntCol3,IntCol4
,case when IntCol5>0 then  IntCol5%@z else null end IntCol5

,case when IntCol5/@z>0 and  IntCol5%@z=0 then  IntCol5/@z-1 
when IntCol5/@z>0 then IntCol5/@z
else null end IntCol6
from
(
select IntCol1,IntCol2,IntCol3
,case when IntCol4>0 then  IntCol4%@z else null end IntCol4

,case when IntCol4/@z>0 and  IntCol4%@z=0 then  IntCol4/@z-1 
when IntCol4/@z>0 then IntCol4/@z
else null end IntCol5
from
(
select IntCol1,IntCol2
,case when IntCol3>0 then  IntCol3%@z else null end IntCol3
,case when IntCol3/@z>0 and  IntCol3%@z=0 then  IntCol3/@z-1 
when IntCol3/@z>0 then IntCol3/@z
else null end IntCol4

from
(
select IntCol1
,case when IntCol2>0 then  IntCol2%@z else null end IntCol2
,case when IntCol2/@z>0 and  IntCol2%@z=0 then  IntCol2/@z-1 
when IntCol2/@z>0 then IntCol2/@z
else null end IntCol3

from
(
select case when N>0 then N%@z else null end IntCol1
,case when N%@z=0 and  (N/@z)>1 then (N/@z)-1 else  (N/@z) end IntCol2 

)Lv2
)Lv3
)Lv4
)Lv5
)LV6

)ca

DROP TABLE NumbersTest1

Có vẻ như bảng dẫn xuất được chuyển đổi thành một vô hướng tính toán có hơn 400000 ký tự mã. Tôi nghi ngờ có rất nhiều chi phí cho tính toán đó. Bạn có thể muốn thử một cái gì đó tương tự như sau: dbfiddle.uk/ Từ Hãy thoải mái tích hợp các thành phần đó vào câu trả lời của bạn.
Joe Obbish
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.