์ด๊ฒ์ ์ค์ ๋ฌธ์ ์์ ์ฝ๊ฐ ๋ฒ์ด๋ ๊ฒ์ ๋๋ค. ์ปจํ ์คํธ ์ ๊ณต์ด ๋์์ด๋๋ ๊ฒฝ์ฐ์ด ๋ฐ์ดํฐ ์์ฑ์ ๋ฌธ์์ด ์ฒ๋ฆฌ ์ฑ๋ฅ ํ ์คํธ ๋ฐฉ๋ฒ, ์ปค์ ๋ด์์ ์ผ๋ถ ์์ ์ ์ ์ฉํด์ผํ๋ ๋ฌธ์์ด ์์ฑ ๋๋ ์ค์ํ ๋ฐ์ดํฐ์ ๋ํ ๊ณ ์ ํ ์ต๋ช ์ด๋ฆ ๋์ฒด๋ฅผ ์์ฑํ๋ ๋ฐ ์ ์ฉ ํ ์ ์์ต๋๋ค. SQL Server์์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ๊ด์ฌ์ด ์์ต๋๋ค.์ด ๋ฐ์ดํฐ๋ฅผ ์์ฑํด์ผํ๋ ์ด์ ๋ฅผ ๋ฌป์ง ๋ง์ญ์์ค.
๋๋ ๋ค์ ๊ณต์์ ์ธ ์ ์๋ก ์์ํ๋ ค๊ณ ํฉ๋๋ค. ๋ฌธ์์ด์ A-Z์ ๋๋ฌธ์๋ก๋ง ๊ตฌ์ฑ๋ ๊ฒฝ์ฐ ์๋ฆฌ์ฆ์ ํฌํจ๋ฉ๋๋ค. ์๋ฆฌ์ฆ์ ์ฒซ ๋ฒ์งธ ์ฉ์ด๋ โAโ์
๋๋ค. ์ด ์๋ฆฌ์ฆ๋ ๊ธธ์ด๊ฐ ๋จผ์ ์ ๋ ฌ๋๊ณ ์ํ๋ฒณ ์์๊ฐ ์ํ๋ฒณ์์ผ๋ก ์ ๋ ฌ ๋ ์ ํจํ ๋ชจ๋ ๋ฌธ์์ด๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ๋ฌธ์์ด์ด์ด๋ผ๋ ์ด์ ํ
์ด๋ธ์ ์์ผ๋ฉด STRING_COL
์์๋ T-SQL์์๋ก ์ ์ ๋ ์ ์์ต๋๋ค ORDER BY LEN(STRING_COL) ASC, STRING_COL ASC
.
๋ ๊ณต์์ ์ผ๋ก ์ ์ํ๋ ค๋ฉด ์ํ๋ฒณ ์ด ๋จธ๋ฆฌ๊ธ์ Excel๋ก ์ดํด๋ณด์ญ์์ค. ์๋ฆฌ์ฆ๋ ๊ฐ์ ํจํด์ ๋๋ค. ์ ์๋ฅผ ๊ธฐ๋ณธ 26 ์ซ์๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ์ญ์์ค.
1-> A, 2-> B, 3-> C, โฆ, 25-> Y, 26-> Z, 27-> AA, 28-> AB, โฆ
โAโ๊ฐ ๊ธฐ๋ณธ 10์์ 0๊ณผ ๋ค๋ฅด๊ฒ ํ๋ํ๊ธฐ ๋๋ฌธ์ ๋น์ ๋ ์๋ฒฝํ์ง ์์ต๋๋ค. ๋ค์์ ํฌ๋ง์ ์ผ๋ก๋ณด๋ค ๋ช ํํ๊ฒํ๊ธฐ ์ํด ์ ํ๋ ๊ฐ์ ํ์ ๋๋ค.
โโโโโโโโโโโโโโฆโโโโโโโโโ
โ 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 โ
โโโโโโโโโโโโโโฉโโโโโโโโโ
๋ชฉํ๋ SELECT
์์ ์ ์ ๋ ์์๋๋ก ์ฒ์ 100000000 ๊ฐ์ ๋ฌธ์์ด์ ๋ฐํ ํ๋ ์ฟผ๋ฆฌ ๋ฅผ ์์ฑํ๋ ๊ฒ์
๋๋ค . SSMS์์ ์ฟผ๋ฆฌ๋ฅผ ์คํํ์ฌ ํ
์ด๋ธ์ ์ ์ฅํ๋ ๋์ ๊ฒฐ๊ณผ ์งํฉ์ ์ญ์ ํ์ฌ ํ
์คํธ๋ฅผ ์ํํ์ต๋๋ค.
์ด์์ ์ผ๋ก๋ ์ฟผ๋ฆฌ๊ฐ ์๋นํ ํจ์จ์ ์ ๋๋ค. ์ฌ๊ธฐ์๋ ์ง๋ ฌ ์ฟผ๋ฆฌ์ CPU ์๊ฐ๊ณผ ๋ณ๋ ฌ ์ฟผ๋ฆฌ์ ๊ฒฝ๊ณผ ์๊ฐ์ ํจ์จ์ ์ผ๋ก ์ ์ํ๊ณ ์์ต๋๋ค. ๋ฌธ์ํ๋์ง ์์ ํธ๋ฆญ์ ์ํ๋๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ ์๋์ง ์์๊ฑฐ๋ ๋ณด์ฅ๋์ง ์์ ํ๋์ ์์กดํ๋ ๊ฒ๋ ๊ด์ฐฎ์ง ๋ง ๋๋ต์์ ๊ทธ๊ฒ์ ๋ถ๋ฌ ์ฃผ๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค.
์์์ ์ค๋ช ํ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ํจ์จ์ ์ผ๋ก ์์ฑํ๋ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น? Martin Smith ๋ CLR ์ ์ฅ ํ๋ก ์์ ๊ฐ ๋๋ฌด ๋ง์ ํ์ ์ฒ๋ฆฌํ๋ ์ค๋ฒ ํค๋๋ก ์ธํด ์ข์ ์ ๊ทผ ๋ฐฉ์์ด ์๋ ์ ์๋ค๊ณ ์ง์ ํ์ต๋๋ค.
๋ต๋ณ
์๋ฃจ์ ์ด ๋ฉํฑ ์์ 35 ์ด ๋์ ์คํ๋ฉ๋๋ค . ๋ค์ ์ฝ๋๋ 26 ์ด๊ฐ ๊ฑธ๋ฆฝ๋๋ค (์์ ํ ์ด๋ธ ์์ฑ ๋ฐ ์ฑ์ฐ๊ธฐ ํฌํจ).
์์ ํ ์ด๋ธ
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;
์ต๋ 4 ์์ ์์๋ก ์กฐํฉ ๋ ํญ๋ชฉ์ ๋ฏธ๋ฆฌ ์ฑ์ฐ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ฉ์ธ ์ฝ๋
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);
์ด๋ ํ์์ ๋ฐ๋ผ 5 ์ ๋ฐ 6 ์ ๋ฌธ์์ด์ด ํ์ ๋ 4 ๊ฐ์ ์ฌ์ ๊ณ์ฐ ๋ ํ ์ด๋ธ์ ๊ฐ๋จํ ์์ ์ ์ง ํตํฉ *์ ๋๋ค. ์ ๋์ฌ์์ ์ ๋์ฌ๋ฅผ ๋ถ๋ฆฌํ๋ฉด ์ ๋ ฌ๋์ง ์์ต๋๋ค.
์คํ ๊ณํ
* ์์ SQL์๋ ์ฃผ๋ฌธ ๋ณด์กด ์ฐํฉ์ ์ง์ ์ง์ ํ๋ ๊ฒ์ด ์์ต๋๋ค . ์ตํฐ๋ง์ด ์ ๋ ์ต์์ ์์๋ฅผ ํฌํจํ์ฌ SQL ์ฟผ๋ฆฌ ์คํ๊ณผ ์ผ์นํ๋ ํน์ฑ์ ๊ฐ์ง ์ค์ ์ฐ์ฐ์๋ฅผ ์ ํํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์ ๋ ฌ์ ํผํ๊ธฐ ์ํด merge join ๋ฌผ๋ฆฌ ์ฐ์ฐ์์ ์ํด ๊ตฌํ ๋ ์ฐ๊ฒฐ์ ์ ํํฉ๋๋ค.
์คํ ๊ณํ์ ์ฌ์์ ๋ฐ๋ผ ์ฟผ๋ฆฌ ์๋งจํฑ ๋ฐ ์ต์์ ์์๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ณํฉ ์กฐ์ธ ์ฐ๊ฒฐ์ด ์์๋ฅผ ์ ์งํ๋ค๋ ๊ฒ์ ์๋ฉด ์ฟผ๋ฆฌ ์์ฑ๊ธฐ๋ ์คํ ๊ณํ์ ์์ ํ ์ ์์ง๋ง ์ตํฐ๋ง์ด ์ ๋ ๊ธฐ๋๊ฐ ์ ํจํ ๊ฒฝ์ฐ์๋ง ์ ๊ณตํฉ๋๋ค.
๋ต๋ณ
์์ํ๊ธฐ ์ํด ๋ต๋ณ์ ๊ฒ์ํ๊ฒ ์ต๋๋ค. ๋ด ์ฒซ ๋ฒ์งธ ์๊ฐ์ ๊ฐ ๋ฌธ์์ ๋ํด ํ๋์ ํ์ด์๋ ๋ช ๊ฐ์ ๋์ฐ๋ฏธ ํ
์ด๋ธ๊ณผ ํจ๊ป ์ค์ฒฉ ๋ฃจํ ์กฐ์ธ์ ์์ ์ ์ง ํน์ฑ์ ํ์ฉํ ์ ์์ด์ผํ๋ค๋ ๊ฒ์
๋๋ค. ๊น๋ค๋ก์ด ๋ถ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๊ธธ์ด๋ณ๋ก ์ ๋ ฌํ๊ณ ์ค๋ณต์ ํผํ๋ ๋ฐฉ์์ผ๋ก ๋ฐ๋ณต๋ฉ๋๋ค. โ์ ํจ๊ป ๋ชจ๋ 26 ๋๋ฌธ์๋ฅผ ํฌํจํ๋ CTE์ ๊ฐ์
ํ ๋ ํฌ๋ก์ค ์๋ฅผ ๋ค์ด, ์์ฑ์ ๋๋ผ ์ 'A' + '' + 'A'
์ '' + 'A' + 'A'
๋ฌผ๋ก ๊ฐ์ ๋ฌธ์์ด์ด๋ค.
์ฒซ ๋ฒ์งธ ๊ฒฐ์ ์ ๋์ฐ๋ฏธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์์น์ ๋๋ค. ์์ ํ ์ด๋ธ์ ์ฌ์ฉํด ๋ณด์์ง๋ง ๋ฐ์ดํฐ๊ฐ ๋จ์ผ ํ์ด์ง์ ์ ํฉํ๋๋ผ๋ ์ฑ๋ฅ์ ๋๋ผ ์ธ ์ ๋๋ก ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์ณค์ต๋๋ค. ์์ ํ ์ด๋ธ์๋ ๋ค์ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
SELECT 'A'
UNION ALL SELECT 'B'
...
UNION ALL SELECT 'Y'
UNION ALL SELECT 'Z'
CTE๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋นํด ์ฟผ๋ฆฌ๋ ํด๋ฌ์คํฐ ๋ ํ ์ด๋ธ์ ๊ฒฝ์ฐ 3 ๋ฐฐ, ํ์ ๊ฒฝ์ฐ 4 ๋ฐฐ ๋ ์ค๋ ๊ฑธ๋ ธ์ต๋๋ค. ๋ฌธ์ ๋ ๋ฐ์ดํฐ๊ฐ ๋์คํฌ์ ์๋ค๊ณ ์๊ฐํ์ง ์์ต๋๋ค. ๋จ์ผ ํ์ด์ง๋ก ๋ฉ๋ชจ๋ฆฌ์ ์ฝ๊ณ ์ ์ฒด ๊ณํ์ ๋ํด ๋ฉ๋ชจ๋ฆฌ์์ ์ฒ๋ฆฌํด์ผํฉ๋๋ค. SQL Server๋ ์ผ๋ฐ์ ์ธ ํ ์ ์ฅ์ ํ์ด์ง์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ณด๋ค Constant Scan ์ฐ์ฐ์์ ๋ฐ์ดํฐ๋ฅผ ๋ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํฅ๋ฏธ๋กญ๊ฒ๋ SQL Server๋ ์ ๋ ฌ ๋ ๋ฐ์ดํฐ๊ฐ์๋ ๋จ์ผ ํ์ด์ง tempdb ํ ์ด๋ธ์ ์ ๋ ฌ ๋ ๊ฒฐ๊ณผ๋ฅผ ํ ์ด๋ธ ์คํ์ ๋ฃ๋๋ก ์ ํํฉ๋๋ค.
SQL Server๋ ๊ต์ฐจ ์กฐ์ธ์ ๋ด๋ถ ํ
์ด๋ธ์ ๋ํ ๊ฒฐ๊ณผ๋ฅผ ์๋ฏธ๊ฐ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋๋ผ๋ ํ
์ด๋ธ ์คํ์ ๋ฃ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ตํฐ๋ง์ด ์ ๋์ด ๋ถ์ผ์์ ์ฝ๊ฐ์ ์์
์ด ํ์ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. NO_PERFORMANCE_SPOOL
์ฑ๋ฅ ์ ํ๋ฅผ ํผํ๊ธฐ ์ํด ์ฟผ๋ฆฌ๋ฅผ ์คํํ์ต๋๋ค .
CTE๋ฅผ ์ฌ์ฉํ์ฌ ํฌํผ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๋ฐ์์ด ํ ๊ฐ์ง ๋ฌธ์ ์ ์ ๋ฐ์ดํฐ์ ์์๊ฐ ๋ณด์ฅ๋์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค. ์ตํฐ๋ง์ด ์ ๊ฐ ์ ์ฃผ๋ฌธํ์ง ์๊ธฐ๋ก ๊ฒฐ์ ํ๋์ง๋ ์ ์ ์์ผ๋ฉฐ ๋ชจ๋ ํ ์คํธ์์ CTE๋ฅผ ์์ฑํ ์์๋๋ก ๋ฐ์ดํฐ๊ฐ ์ฒ๋ฆฌ๋์์ต๋๋ค.
๊ทธ๋ฌ๋ ํนํ ์ฑ๋ฅ ์ค๋ฒ ํค๋๊ฐ ํฌ์ง ์์ ๊ฒฝ์ฐ์๋ ์ํ ํ ์์๋ ๊ธฐํ๊ฐ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ถํ์ํ TOP
์ฐ์ฐ์ ๋ฅผ ์ถ๊ฐํ์ฌ ํ์ ํ
์ด๋ธ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฌ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
(SELECT TOP (26) CHR FROM FIRST_CHAR ORDER BY CHR)
์ฟผ๋ฆฌ์ ์ถ๊ฐํ๋ฉด ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฐ๋ฅธ ์์๋ก ๋ฐํ๋ฉ๋๋ค. ๋ชจ๋ ์ข ๋ฅ์ ์ฑ๋ฅ์ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น ๊ฒ์ผ๋ก ์์ํ์ต๋๋ค. ์ฟผ๋ฆฌ ์ต์ ํ ํ๋ก๊ทธ๋จ์ ์์ ๋น์ฉ์ ๊ธฐ๋ฐ์ผ๋ก์ด๋ฅผ ์์ธกํ์ต๋๋ค.
๋๋๊ฒ๋, ๋ช
์ ์ ์์์ ์ ๋ฌด์ ๊ด๊ณ์์ด CPU ์๊ฐ ๋๋ ๋ฐํ์์์ ํต๊ณ์ ์ผ๋ก ์ ์ ํ ์ฐจ์ด๋ฅผ ๊ด์ฐฐ ํ ์ ์์์ต๋๋ค. ๋ฌด์์ด๋ , ์ฟผ๋ฆฌ๋ ORDER BY
! ์ด ๋์์ ๋ํ ์ค๋ช
์ด ์์ต๋๋ค.
๋ฌธ์ ์ ๊น๋ค๋ก์ด ๋ถ๋ถ์ ์ฌ๋ฐ๋ฅธ ์์น์ ๊ณต๋ฐฑ ๋ฌธ์๋ฅผ ์ฝ์
ํ๋ ๋ฐฉ๋ฒ์ ์์๋ด๋ ๊ฒ์ด ์์ต๋๋ค. ์์์ ์ธ๊ธํ๋ฏ์ด ๊ฐ๋จํ CROSS JOIN
๋ฐ์ดํฐ๋ ์ค๋ณต๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก 100000000 ๋ฒ์งธ ๋ฌธ์์ด์ ๊ธธ์ด๊ฐ 6 ์๋ผ๋ ๊ฒ์ ์๊ณ ์์ต๋๋ค.
26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 = 914654 <100000000
๊ทธ๋ฌ๋
26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 + 26 ^ 6 = 321272406> 100000000
๋ฐ๋ผ์ CTE์ 6 ๋ฒ๋ง ๊ฐ์
ํ๋ฉด๋ฉ๋๋ค. CTE์ 6 ๋ฒ ๊ฐ์
ํ๊ณ ๊ฐ CTE์์ ํ ๊ธ์๋ฅผ ๊ฐ์ ธ ์์ ๋ชจ๋ ์ฐ๊ฒฐํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ๊ฐ์ฅ ์ผ์ชฝ์ ๋ฌธ์๊ฐ ๊ณต๋ฐฑ์ด ์๋๋ผ๊ณ ๊ฐ์ ํ์ญ์์ค. ํ์ ๋ฌธ์๊ฐ ๋น์ด ์์ผ๋ฉด ๋ฌธ์์ด์ ๊ธธ์ด๊ฐ 6 ์ ๋ฏธ๋ง์ด๋ฏ๋ก ์ค๋ณต๋ฉ๋๋ค. ๋ฐ๋ผ์ ๊ณต๋ฐฑ์ด ์๋ ์ฒซ ๋ฒ์งธ ๋ฌธ์๋ฅผ ์ฐพ์ ๊ณต๋ฐฑ์ด ์๋ ๋ชจ๋ ๋ฌธ์๋ฅผ ์๊ตฌํ์ฌ ์ค๋ณต์ ๋ฐฉ์ง ํ ์ ์์ต๋๋ค. FLAG
CTE ์ค ํ๋์ ์ด์ ํ ๋น ํ๊ณ WHERE
์ ์ ๊ฒ์ฌ๋ฅผ ์ถ๊ฐํ์ฌ ์ด๋ฅผ ์ถ์ ํ๊ธฐ๋ก ์ ํํ์ต๋๋ค . ์ฟผ๋ฆฌ๋ฅผ ํ์ธํ ํ์ ๋ ๋ช
ํํด์ผํฉ๋๋ค. ์ต์ข
์ฟผ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
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);
CTE๋ ์ ์ ํ ๋ฐ์ ๊ฐ๋ค. ALL_CHAR
๋น ๋ฌธ์์ ๋ํ ํ์ด ํฌํจ๋์ด ์๊ธฐ ๋๋ฌธ์ 5 ๋ฒ ์ฐ๊ฒฐ๋ฉ๋๋ค. ๋ฌธ์์ด์ ๋ง์ง๋ง ๋ฌธ์๋ ๋น์ ๋ ์ ์์ผ๋ฏ๋ก ๋ณ๋์ CTE๊ฐ ์ ์๋ฉ๋๋ค FIRST_CHAR
. ์ถ๊ฐ ํ๋๊ทธ ์ด ALL_CHAR
์ ์์์ ์ค๋ช
ํ๋๋ก ์ค๋ณต์ ๋ฐฉ์งํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด ๊ฒ์ฌ๋ฅผ ์ํํ๋ ๋ฐ ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ด์์ ์ ์์ง๋ง ๋ ๋นํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ํ๋ ๊ฐ ๋์ ์ํ์ฌ ์๋ LEN()
ํ๊ณ POWER()
ํ์ฌ ๋ฒ์ ๋ณด๋ค ์ฌ์ฏ ๋ฐฐ ๋๋ฆฐ ์ฟผ๋ฆฌ ์คํ์ํ๋ค.
MAXDOP 1
์ FORCE ORDER
ํํธ๋ ํ์ธ ์ฃผ๋ฌธ์ด ์ฟผ๋ฆฌ์ ๋ณด์กด๋์ด ์๋์ง ํ์ธํ๋ ๊ฒ์ด ํ์์ ์ด๋ค. ์ฃผ์์ด ๋ฌ๋ฆฐ ์ถ์ ๊ณํ์ ์กฐ์ธ์ด ํ์ฌ ์์ ์ธ ์ด์ ๋ฅผ ํ์ธํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
์ฟผ๋ฆฌ ๊ณํ์ ์ข
์ข
์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฝ์ง ๋ง ํ ์์ฒญ์ ์ผ์ชฝ์์ ์ค๋ฅธ์ชฝ์ผ๋ก ๋ฐ์ํฉ๋๋ค. ์ด์์ ์ผ๋ก SQL Server๋ d1
์์ ์ค์บ ์ฐ์ฐ์์๊ฒ ์ ํํ 1 ์ต ๊ฐ์ ํ์ ์์ฒญํฉ๋๋ค . ์ผ์ชฝ์์ ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋ํ ๋ ๊ฐ ์ฐ์ฐ์์์ ๋ ์ ์ ์์ ํ์ ์์ฒญํ ๊ฒ์ผ๋ก ์์ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ด๊ฒ์ ์ค์ ์คํ ๊ณํ ์์ ๋ณผ ์ ์์ต๋๋ค . ๋ํ ์๋๋ SQL Sentry Plan Explorer์ ์คํฌ๋ฆฐ ์ท์
๋๋ค.
์ฐ๋ฆฌ๋ d1์์ ์ ํํ 1 ์ต ๊ฐ์ ํ์ ์ป์์ต๋๋ค. d2์ d3 ์ฌ์ด์ ํ ๋น์จ์ ๊ฑฐ์ ์ ํํ 27 : 1 (165336 * 27 = 4464072)์ด๋ฏ๋ก ํฌ๋ก์ค ์กฐ์ธ์ ์๋ ๋ฐฉ์์ ๋ํด ์๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค. d1๊ณผ d2 ์ฌ์ด์ ํ ๋น์จ์ 22.4์ด๋ฉฐ ์ผ๋ถ ๋ญ๋น ๋ ์์ ์ ๋ํ๋ ๋๋ค. ์ฌ๋ถ์ ํ์ ์ค๋ณต ๋ ๊ฒ (๋ฌธ์์ด ์ค๊ฐ์ ๋น ๋ฌธ์๋ก ์ธํด)์์ ๋์จ ๊ฒ์ผ๋ก ํํฐ๋ง์ ์ํํ๋ ์ค์ฒฉ ๋ฃจํ ์กฐ์ธ ์ฐ์ฐ์๋ฅผ ์ง๋์น์ง ์์ต๋๋ค.
LOOP JOIN
๋๋ฌธ์ ํํธ๋ ๊ธฐ์ ์ ์ผ๋ก ํ์ํ์ง ์์ต๋๋ค CROSS JOIN
๋ง ๋ฃจํ๋ก ๊ตฌํ ๋ ์๋ SQL ์๋ฒ์ ๊ฐ์
ํ ์ ์์ต๋๋ค. ๋ NO_PERFORMANCE_SPOOL
๋ถํ์ํ ํ
์ด๋ธ ์คํ๋ง์ ๋ฐฉ์งํ๋ ๊ฒ์
๋๋ค. ์คํ ํํธ๋ฅผ ์๋ตํ๋ฉด ์ฟผ๋ฆฌ๊ฐ ์ปดํจํฐ์์ 3 ๋ฐฐ ๋ ์ค๋ ๊ฑธ๋ ธ์ต๋๋ค.
์ต์ข ์ฟผ๋ฆฌ์ CPU ์๊ฐ์ ์ฝ 17 ์ด์ด๊ณ ์ด ๊ฒฝ๊ณผ ์๊ฐ์ 18 ์ด์ ๋๋ค. SSMS๋ฅผ ํตํด ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ ์งํฉ์ ๋ฒ๋ฆด โโ๋์์ต๋๋ค. ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๋ณด๋ ๋ฐ ๊ด์ฌ์ด ์์ต๋๋ค.
๋ต๋ณ
์ต๋ 217,180,147,158 (8 ์)๊น์ง ํน์ ์ซ์์ ๋ฌธ์์ด ์ฝ๋๋ฅผ ์ป๋๋ก ์ต์ ํ ๋ ์๋ฃจ์ ์ด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ ๋น์ ์ ์๊ฐ์ ์ด๊ธธ ์ ์์ต๋๋ค :
๋ด ์ปดํจํฐ์์ SQL Server 2014๋ฅผ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ์ 18 ์ด๊ฐ ๊ฑธ๋ฆฌ๊ณ ๊ด์ฐ์๋ 3m 46s๊ฐ ๊ฑธ๋ฆฝ๋๋ค. 2014๋ NO_PERFORMANCE_SPOOL
ํํธ๋ฅผ ์ง์ํ์ง ์์ผ๋ฏ๋ก ๋ ์ฟผ๋ฆฌ ๋ชจ๋ ๋ฌธ์ํ๋์ง ์์ ์ถ์ ํ๋๊ทธ 8690์ ์ฌ์ฉํฉ๋๋ค .
์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
/* 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);
์ฌ๊ธฐ์ ์์์๋ ๋ค๋ฅธ ์์ด์ด ์์๋๋ ์์น๋ฅผ ๋ฏธ๋ฆฌ ๊ณ์ฐํ๋ ๊ฒ์ ๋๋ค.
- ๋จ์ผ ๋ฌธ์๋ฅผ ์ถ๋ ฅํด์ผ ํ ๊ฒฝ์ฐ 26 ^ 0์์ ์์ํ๋ 26 ^ 1 ์์ด์ด ์์ต๋๋ค.
- 2 ๊ฐ์ ๋ฌธ์๋ฅผ ์ถ๋ ฅํด์ผ ํ ๊ฒฝ์ฐ 26 ^ 0 + 26 ^ 1์์ ์์ํ๋ 26 ^ 2 ์์ด์ด ์์ต๋๋ค.
- 3 ๊ฐ์ ๋ฌธ์๋ฅผ ์ถ๋ ฅํด์ผ ํ ๋ 26 ^ 0 + 26 ^ 1 + 26 ^ 2์์ ์์ํ๋ 26 ^ 3 ์์ด์ด ์์ต๋๋ค.
- n ์ ๋ฐ๋ณต
์ฌ์ฉ๋๋ ๋ค๋ฅธ ํธ๋ฆญ์ ๋จ์ํ ์ฐ๊ฒฐํ๋ ๋์ sum์ ์ฌ์ฉํ์ฌ ์ฌ๋ฐ๋ฅธ ๊ฐ์ ์ป๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ๋ฌ์ฑํ๊ธฐ ์ํด ๊ฐ๋จํ ์ซ์ 26์ ๊ธฐ๋ณธ 256์ผ๋ก ์คํ์ ํ๊ณ ๊ฐ ์ซ์์ ๋ํด โAโ์ ASCII ๊ฐ์ ์ถ๊ฐํฉ๋๋ค. ๋ฐ๋ผ์ ์ฐพ๊ณ ์๋ ๋ฌธ์์ด์ ์ด์ง ํํ์ ์ป์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ผ๋ถ ๋ฌธ์์ด ์กฐ์์ผ๋ก ํ๋ก์ธ์ค๊ฐ ์๋ฃ๋ฉ๋๋ค.
๋ต๋ณ
์ข์, ์ฌ๊ธฐ ๋ด ์ต์ ์คํฌ๋ฆฝํธ๊ฐ ๊ฐ๋ค.
๋ฃจํ ์์, ์ฌ๊ท ์์.
6 ์๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค
๊ฐ์ฅ ํฐ ๋จ์ ์ 1,00,00,000์ ์ฝ 22 ๋ถ์ด ๊ฑธ๋ฆฐ๋ค๋ ๊ฒ์ ๋๋ค
์ด๋ฒ์๋ ๋ด ์คํฌ๋ฆฝํธ๊ฐ ๋งค์ฐ ์งง์ต๋๋ค.
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