SlideShare a Scribd company logo
Common Table Expressions
By MySQL 8.0 LAB
2017.01.14 (MySQL Power Group)
1
2
Index
 Common Table Expression (CTE) 이란?
 Non-recursive common table expression
 Recursive common table expression
 Appendix
3
Common Table Expression
 MySQL 8.0 Labs Release 된 New Feature!
 기존 파생 테이블은 From절에 subquery 로 표현
SELECT … FROM (subquery) AS drived, t1 …
 Common Table Expression(CTE)는 파생테이블과 비슷하지만,
From 절 대신 쿼리 블록 앞에 선언!
WITH derived
AS (subquery)
SELECT… FROM derived, t1…
 CTE는 subquery가 포함된 SELECT/UPDATE/DELETE에도 사용 가능
WITH derived
AS (subquery)
DELETE FROM t1 WHERE t1.a IN (SELECT b from derived);
4
EX) SELECT
CREATE TABLE t1
(
a INT
, b INT
);
INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
WITH qn AS
(
SELECT a+2 AS a, b
FROM t1
)
SELECT *
FROM qn;
Common Table Expression - select
5
Common Table Expression - update
EX) UPDATE
WITH qn AS
(
SELECT a+2 AS a, b
FROM t1
)
UPDATE t1, qn
SET t1.a=qn.a+10
WHERE t1.a = qn.a;
SELECT *
FROM t1;
self join을
CTE로 작성할 수 있다.
6
Common Table Expression - delete
EX) DELETE
WITH qn AS
(
SELECT a+2 AS a, b
FROM t1
)
DELETE t1
FROM t1, qn
WHERE t1.a = qn.a;
SELECT *
FROM t1;
7
Common Table Expression - insert
EX) INSERT
INSERT INTO t2
WITH qn AS
(
SELECT 10*a AS a
FROM t1
)
SELECT *
FROM qn;
SELECT *
FROM t2
8
CTE vs 파생테이블
Better readability
Can be referenced multiple times
Can refer to other CTEs
Improved Performance
9
Better readability
• 파생테이블 :
SELECT *
FROM t1
LEFT OUTER JOIN (
SELECT *
FROM t2) AS t2 ON t1.id = t2.id
LEFT OUTER JOIN (
SELECT *
FROM t3) AS t3 ON t1.id = t2.id;
• CTE :
WITH t2 AS(
SELECT *
FROM t2
), t3 AS(
SELECT *
FROM t3
)
SELECT *
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id
LEFT OUTER JOIN t2 ON t1.id = t3.id;
10
Can be referenced multiple times
• 파생테이블 :
SELECT *
FROM (SELECT ProductID, COUNT(*) FROM Orders GROUP BY ProductID) A
INNER JOIN
(SELECT ProductID, COUNT(*) FROM Orders GROUP BY ProductID) B
ON A.ProductID = B.ProductID;
• CTE :
WITH CTE AS
(
SELECT ProductID, COUNT(*) AS Cnt
FROM Orders
GROUP BY ProductID
)
SELECT *
FROM CTE A
INNER JOIN CTE B ON A.ProductID = B.ProductID;
11
Can refer to other CTEs
• 파생테이블 :
SELECT *
FROM (SELECT * FROM Products) A, (SELECT * FROM A) B
ERROR : 1146 : Table `A` doesn’t exists
• CTE :
WITH A AS( SELECT * FROM Prouducts)
, B AS( SELECT * FROM A)
SELECT *
FROM A;
 products 테이블은 한번만 참조!
12
Chained CTEs
WITH cte1(txt) AS ( SELECT "This " )
, cte2(txt) AS ( SELECT CONCAT(cte1.txt,"is a ")
FROM cte1)
, cte3(txt) AS ( SELECT "nice query" UNION
SELECT "query that rocks" UNION
SELECT "query")
, cte4(txt) AS ( SELECT concat(cte2.txt, cte3.txt)
FROM cte2, cte3
)
SELECT MAX(txt), MIN(txt)
FROM cte4;
MAX(txt) MIN(txt)
This is a query that rocks This a nice query
좋은 예는 아니지만, 이렇게도 쓸 수 있습니다.
txt
This is a nice query
This is a query that rocks
This is a query
13
****테스트 데이터 생성***
-- 1~1000 상품 생성
CREATE TABLE Products
SELECT @rownum :=@rownum+1 AS ProductID
, CAST(RAND()*100000 AS UNSIGNED) AS Price
FROM information_schema.columns A
, (SELECT @rownum := 0) B
LIMIT 1000;
-- 1,000,000건 주문 데이터 생성
CREATE TABLE Orders
SELECT DATE_ADD('2010-01-01', INTERVAL CAST(RAND()*3000000 AS UNSIGNED) MINUTE) AS OrderDate
, CAST(RAND()*1000 AS UNSIGNED) AS ProductID
, CAST(RAND()*100000 AS UNSIGNED)
FROM information_schema.columns A
, information_schema.columns B
, information_schema.columns C
LIMIT 1000000;
ALTER TABLE Products ADD PRIMARY KEY (ProductID);
CREATE INDEX Idx_Orders01 ON Orders (OrderDate);
CREATE INDEX Idx_Orders02 ON Orders (ProductID);
Improved Performance
Products
ProductID (PK)
Price
Orders
OrderDate
ProductID
UserID
14
Improved Performance - view
CREATE VIEW v_Orders
AS
SELECT A.ProductID, SUM(B.Price) AS TotPrice, COUNT(*) AS orderCount
FROM Orders A
INNER JOIN Products B ON A.ProductID = B.ProductID
GROUP BY A.ProductID;
SELECT *
FROM Products A, v_Orders B
WHERE A.ProductID = B.ProductID
AND A.ProductID = (SELECT MAX(ProductID) FROM v_Orders);
ProductID Price ProductID TotPrice orderCount
1000 55523 1000 30537650 550
1 row in set (1.74 sec)
 v_Orders를 두 번 사용할 경우입니다.
15
SubQuery
Orders
Orders
GROUP
GROUP
SELECT
JOIN
Products
Improved Performance - view
16
WITH CTE AS(
SELECT A.ProductID, SUM(B.Price) AS TotPrice, COUNT(*) AS orderCount
FROM Orders A
INNER JOIN Products B ON A.ProductID = B.ProductID
GROUP BY A.ProductID
)
SELECT *
FROM Products A
, CTE B
WHERE A.ProductID = B.ProductID
AND A.ProductID = (SELECT MAX(ProductID) FROM CTE);
Improved Performance - CTE
ProductID Price ProductID TotPrice orderCount
1000 55523 1000 30537650 550
1 row in set (0.70 sec)
17
SubQuery
OrdersGROUP
SELECT
JOIN
Products
SubQuery
Improved Performance - CTE
18
Improved Performance
0
0.5
1
1.5
2
View CTE
QueryExecutionTime(Seconds)
1.74 sec
0.70 sec
19
Recursive 란?
def countdown(n):
if n == 0:
print "Blastoff!"
else:
print n
countdown(n-1);
>>> countdown(3)
3
2
1
Blastoff!
함수가 자기 자신을 호출하는 것!
Countdown(n)
n == 0
종료!
n=n-1
20
Recursive CTE
WITH RECURSIVE cte AS(
SELECT … FROM table_name /* “seed” SELECT */
UNION ALL
SELECT … FROM cte, table_name /* “recursive” SELECT */
)
SELECT … FROM cte;
• “seed” SELECT를 한 번 실행하여 초기 데이터 하위 집합을 만들고
재귀 SELECT를 반복 실행하여 전체 결과 집합이 얻어 질 때까지 데이터의 하위
집합을 반환함
• 새로운 Row가 생기지 않을 경우 재귀가 중지됨.
• 계층 구조 쿼리를 작성하는데 유용 (부모/자식, 부분/하위)
21
Recursive CTE – Example 1
Print 1 to 10 :
WITH RECURSIVE num AS (
SELECT 1 AS n  Seed
UNION ALL
SELECT 1+n FROM num WHERE n < 10  Recursive
)
SELECT n FROM num;
n
1
2
3
4
5
6
7
8
9
10
22
Fibonacci Numbers :
0과 1로 시작하며,
다음 피보나치 수는 바로 앞의 두 피보나치 수의 합이 된다.
WITH RECURSIVE num AS (
SELECT 1 AS n, 1 AS n1, 1 AS n2
UNION ALL
SELECT 1+n, n2, n1+n2
FROM num
WHERE n < 10
)
SELECT n, n1, n2
FROM num;
Recursive CTE – Example 2
n n1 n2
1 1 1
2 1 2
3 2 3
4 3 5
5 5 8
6 8 13
7 13 21
8 21 34
9 34 55
10 55 89
23
Recursive CTE – Example 3
4-digit bit string print (1/3)
WITH RECURSIVE digits AS
(
SELECT '0' AS d
UNION ALL
SELECT '1'
),
strings AS
(
SELECT CAST('' AS CHAR(4)) AS s
UNION ALL
SELECT CONCAT(strings.s, digits.d)
FROM strings, digits
WHERE LENGTH(strings.s) < 4
)
SELECT *
FROM strings
WHERE LENGTH(s)=4;
24
S
0
1
S
0
1
S
0 0
0 1
1 0
1 1
S
0
1
……….
Recursive CTE – Example 3
해당 구문이 없으면 문자
열 크기가 char(1)로 정해
져 버린다.
WITH RECURSIVE digits AS
(
SELECT '0' AS d
UNION ALL
SELECT '1'
),
strings AS
(
SELECT CAST('' AS CHAR(4)) AS s
UNION ALL
SELECT CONCAT(strings.s, digits.d)
FROM strings, digits
WHERE LENGTH(strings.s) < 4
)
SELECT *
FROM strings
WHERE LENGTH(s)=4;
4-digit bit string print (2/3)
25
Recursive CTE – Example 3
4-digit bit string print (3/3)
WITH RECURSIVE digits AS
(
SELECT '0' AS d
UNION ALL
SELECT '1'
),
strings AS
(
SELECT CAST('' AS CHAR(4)) AS s
UNION ALL
SELECT CONCAT(strings.s, digits.d)
FROM strings, digits
WHERE LENGTH(strings.s) < 4
)
SELECT *
FROM strings
WHERE LENGTH(s)=4;
26
Recursive CTE – Example 4
CREATE TABLE MyEmployees
(
EmployeeID VARCHAR(100) NOT NULL,
EmployeeName NVARCHAR(30) NOT NULL,
ManagerID INT NULL,
PRIMARY KEY (EmployeeID )
);
INSERT INTO MyEmployees VALUES
(1, N'유재석',NULL)
,(273, N'박명수',1)
,(274, N'정준하',1)
,(275, N'하하',273)
,(276, N'양세형',274)
,(285, N'황광희',273)
,(286, N'정형돈',276)
,(16, N'노홍철', 285)
,(23, N'길', 16);
1 유재석
273 박명수 274 정준하
275 하하
16 노홍철
23 길
285 황광희 276 양세형
286 정형돈
27
Recursive CTE – Example 4
WITH RECURSIVE EmployeeOrder AS (
SELECT EmployeeID, EmployeeName, 1 AS LEVEL, EmployeeID AS Path
FROM MyEmployees
WHERE ManagerID IS NULL
UNION ALL
SELECT A.EmployeeID, A.EmployeeName, LEVEL + 1, CONCAT(B.Path, ',', A.EmployeeID)
FROM MyEmployees A
INNER JOIN EmployeeOrder B ON A.ManagerID = B.EmployeeID
)
SELECT *
FROM EmployeeOrder;
1. 재귀적 CTE 인 EmployeeOrder는 Seed와 Recursive를 정의함
2. Seed는 직급이 가장 높은 (ManagerID is NULL)로 정의함
3. Level은 Tree의 depth이고, Path는 경로를 나타냄
EmplyeeID EmployeeName Level Path
1 유재석 1 1
[Seed]
28
4. Recursive는 Seed 결과 집합에 있는 직원의 직속 하급자를 반환함
Employee 테이블과 EmployeeOrder CTE 간의 조인작업을 통해 수행되며
첫 번째 반복작업은 다음 결과가 Return 됨
Recursive CTE – Example 4
EmplyeeID EmployeeName Level Path
1 유재석 1 1
273 박명수 2 1,273
274 정준하 2 1,274
29
5. Recursive가 반복적으로 활성화되며,
273, 274를 ManagerID로 가지고 있는 결과를 반환함
EmplyeeID EmployeeName Level Path
1 유재석 1 1
273 박명수 2 1,273
274 정준하 2 1,274
275 하하 3 1,273,275
276 양세형 3 1,274,275
285 황광희 3 1,273,258
Recursive CTE – Example 4
30
WITH RECURSIVE EmployeeOrder AS (
SELECT EmployeeID, EmployeeName, 1 AS LEVEL, EmployeeID AS Path
FROM MyEmployees
WHERE ManagerID IS NULL
UNION ALL
SELECT A.EmployeeID, A.EmployeeName, LEVEL + 1, CONCAT(B.Path, ',', A.EmployeeID)
FROM MyEmployees A
INNER JOIN EmployeeOrder B ON A.ManagerID = B.EmployeeID
)
SELECT *
FROM EmployeeOrder;
Recursive CTE – Example 4
EmployeeID EmployeeName Level Path
1 유재석 1 1
273 박명수 2 1,273
274 정준하 2 1,274
275 하하 3 1,273,275
276 양세형 3 1,274,276
285 황광희 3 1,273,285
16 노홍철 4 1,273,285,16
286 정형돈 4 1,274,276,286
23 길 5 1,273,285,16,23
31
Recursive CTE
• 계층적 데이터를 조작 및 구현을 쉽게 할 수 있음
 회사 계급 구조
 메뉴 구조
 가족 관계
 주소
 게시판 등등…
• Recursive CTE에 SELECT 절에는 아래 예약어가 포함될 수 없음
 GROUP BY
 Aggregate function (SUM, MAX….)
 ORDER BY
 LIMIT
 DISTINCT
32
Recursive CTE – Example 4
 특정직원(정준하)의 부하를 찾아보자!
WITH RECURSIVE EmployeeOrder AS (
SELECT EmployeeID, EmployeeName, 1 AS LEVEL, EmployeeID AS Path
FROM MyEmployees
WHERE EmployeeID = 274 (정준하)
UNION ALL
SELECT A.EmployeeID, A.EmployeeName, LEVEL + 1, CONCAT(B.Path, ',', A.EmployeeID)
FROM MyEmployees A
INNER JOIN EmployeeOrder B ON A.ManagerID = B.EmployeeID
)
SELECT *
FROM EmployeeOrder
EmplyeeID EmployeeName Level Path
274 정준하 1 274
276 양세형 2 274,276
286 정형돈 3 274.276,286
33
Recursive CTE – Example 4
 특정직원(정형돈)의 상사를 찾아보자!
WITH RECURSIVE EmployeeOrder AS (
SELECT ManagerID, EmployeeName, 1 AS LEVEL
FROM MyEmployees
WHERE EmployeeID = 286 (정형돈)
UNION ALL
SELECT A.ManagerID, A.EmployeeName, 1+LEVEL
FROM MyEmployees A
INNER JOIN EmployeeOrder B ON A.EmployeeID = B.ManagerID
)
SELECT *
FROM EmployeeOrder
ManagerID EmployeeName Level
276 정형돈 1
274 양세형 2
1 정준하 3
NULL 유재석 4
 탐색이 역순이기 때문에 path는 별도 Join으로
나타내어야 함
34
Index
 Common Table Expression (CTE) 이란?
 Non-recursive common table expression
 Recursive common table expression
 Appendix
# Descending Index
35
Descending Indexes
 MySQL 8.0 부터는 Descending Index 지원 !!
mysql 5.6> CREATE TABLE t1 (a INT, b INT, INDEX a_desc_b_asc (a DESC, b ASC));
Query OK, 0 rows affected (0.47 sec)
mysql 5.6> SHOW CREATE TABLE t1G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
KEY `a_desc_b_asc` (`a`,`b`)  Descending 인덱스로 생성이 되지 않는다.
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4
1 row in set (0.00 sec)
mysql 8.0> CREATE TABLE t1 (a INT, b INT, INDEX a_desc_b_asc (a DESC, b ASC));
Query OK, 0 rows affected (0.47 sec)
mysql 8.0 > SHOW CREATE TABLE t1G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
KEY `a_desc_b_asc` (`a` DESC,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4
1 row in set (0.00 sec)
36
Descending Indexes
Test 환경 (공통)
H/W
- Amazon EC2 (t2.medium) CPU : 2Core / Memory : 4GB
OS
- Amazon Linux
비교 DBMS
- MySQL 8.0 Labs
- MySQL 5.6.29
CREATE TABLE descendingTable
(
ID INT DEFAULT NULL,
LEVEL INT DEFAULT NULL,
KEY (ID DESC, LEVEL ASC)
);
INSERT INTO descendingTable
SELECT CAST(RAND()*100000 AS UNSIGNED) AS ID
, CAST(RAND()*100 AS UNSIGNED) AS LEVEL
FROM information_schema.columns A, information_schema.columns B, information_schema.columns C
LIMIT 1000000;
37
Descending Indexes - 1
mysql 5.6> SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000;
Query OK, 1000 rows affected (0.044 sec)
mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000;
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- --------------- ------ ------------- ------ ------- ------ ------ -------------
1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index
mysql 8.0> SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000;
Query OK, 1000 rows affected (0.042 sec)
mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000;
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- --------------- ------ ------------- ------ ------- ------ ------ -------------
1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index
ID DESC,
LEVEL ASC
⇒
ID ASC,
LEVEL ASC
ID DESC,
LEVEL ASC
38
Descending Indexes - 2
mysql 5.6> SELECT * FROM descendingTable ORDER BY ID ASC LIMIT 1000;
Query OK, 1000 rows affected (0.042 sec)
mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID LIMIT 1000;
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- --------------- ------ ------------- ------ ------- ------ ------ -------------
1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index
mysql 8.0> SELECT * FROM descendingTable ORDER BY ID ASC LIMIT 1000;
Query OK, 1000 rows affected (0.042 sec)
mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID LIMIT 1000;
partitions type possible_keys key key_len ref rows filtered Extra
---------- ------ ------------- ------ ------- ------ ------ -------- ----------------------------------
(NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Backward index scan
Descending 인덱스가 지원되면서 Backward index scan이라는 연산이 생김
ID DESC,
LEVEL ASC
ID DESC,
LEVEL ASC
⇒
ID ASC,
LEVEL ASC
39
Descending Indexes - 3
mysql 5.6> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL ASC LIMIT 1000;
Query OK, 1000 rows affected (0.455 sec)
mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL LIMIT 1000;
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- --------------- ------ ------------- ------ ------- ------ ------ -----------------------------
1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 998412 Using index; Using filesort
mysql 8.0> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL ASC LIMIT 1000;
Query OK, 1000 rows affected (0.042 sec)
mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL LIMIT 1000;
partitions type possible_keys key key_len ref rows filtered Extra
---------- ------ ------------- ------ ------- ------ ------ -------- -------------
(NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index;
• 정렬 조건이 내림/올림 차순이 혼재해 있을 경우
MySQL 5.6버전에서는 Filesort가 발생되며 그 수행속도 차이는 매우 큼
ID DESC,
LEVEL ASC
ID DESC,
LEVEL ASC
⇒
ID ASC,
LEVEL ASC
40
Descending Indexes - 4
mysql 5.6> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000;
Query OK, 1000 rows affected (0.457 sec)
mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000;
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- --------------- ------ ------------- ------ ------- ------ ------ -----------------------------
1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 998412 Using index; Using filesort
mysql 8.0> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000;
Query OK, 1000 rows affected (0.042 sec)
mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000;
partitions type possible_keys key key_len ref rows filtered Extra
---------- ------ ------------- ------ ------- ------ ------ -------- ----------------------------------
(NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Backward index scan
• MySQL 8.0 에서는 backward index scan을 수행하므로, filesort 없이 빠른 처리가 가능
ID DESC,
LEVEL ASC
ID DESC,
LEVEL ASC
⇒
ID ASC,
LEVEL ASC
41
Descending Indexes - 5
mysql 5.6> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000;
Query OK, 1000 rows affected (0.044 sec)
mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000;
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- --------------- ------ ------------- ------ ------- ------ ------ -------------
1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index
mysql 8.0> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000;
Query OK, 1000 rows affected (0.452 sec)
mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000;
partitions type possible_keys key key_len ref rows filtered Extra
---------- ------ ------------- ------ ------- ------ ------ -------- ----------------------------------
(NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Using Filesort
• 정의가 되어 있지 않은 정렬을 하므로 MySQL 8.0에서도 filesort가 발생함.
이는 적절한 인덱스를 생성하여 filesort를 방지할 수 있음
ex) (ID DESC, LEVEL DESC) or (ID ASC, LEVEL ASC)
ID DESC,
LEVEL ASC
ID DESC,
LEVEL ASC
⇒
ID ASC,
LEVEL ASC
42
Descending Indexes - 6
mysql 5.6> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000;
Query OK, 1000 rows affected (0.457 sec)
mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000;
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- --------------- ------ ------------- ------ ------- ------ ------ -------------
1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index
mysql 8.0> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000;
Query OK, 1000 rows affected (0.042 sec)
mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000;
partitions type possible_keys key key_len ref rows filtered Extra
---------- ------ ------------- ------ ------- ------ ------ -------- ----------------------------------
(NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Using Filesort
ID DESC,
LEVEL ASC
ID DESC,
LEVEL ASC
⇒
ID ASC,
LEVEL ASC
43
• MySQL 5.7에서는 query3/4 같은 쿼리의 성능을 향상 시킬 수가 없었으나,
MySQL 8.0부터는 Descending Index 를 통해 성능 향상을 할 수 있음
결론
44

More Related Content

PDF
The MySQL Query Optimizer Explained Through Optimizer Trace
PDF
SWP - A Generic Language Parser
KEY
Postgres rules
DOCX
Clips basics how to make expert system in clips | facts adding | rules makin...
PDF
Disassembling Go
PDF
The Ring programming language version 1.5.4 book - Part 22 of 185
PDF
Functional programming from its fundamentals
The MySQL Query Optimizer Explained Through Optimizer Trace
SWP - A Generic Language Parser
Postgres rules
Clips basics how to make expert system in clips | facts adding | rules makin...
Disassembling Go
The Ring programming language version 1.5.4 book - Part 22 of 185
Functional programming from its fundamentals

What's hot (19)

ODP
PPT
SQL querys in detail || Sql query slides
PDF
Haskell 101
PDF
Powerful Explain in MySQL 5.6
PDF
MySQL understand Indexes
PPT
SQL || overview and detailed information about Sql
PPTX
Optimizing queries MySQL
PDF
Go internals (Go Israel Meetup)
PPTX
Pemrograman Terstruktur 4
ODP
Chetan postgresql partitioning
PDF
MySQL Optimizer: What’s New in 8.0
PPTX
Sql
PDF
MariaDB Optimizer - further down the rabbit hole
PDF
[INSIGHT OUT 2011] B24 effective indexing(tom kyte)
PDF
PythonOOP
PDF
learn you some erlang - chap0 to chap2
PPTX
CQL 实现
PPT
sql statement
PDF
Python Lab Manual
SQL querys in detail || Sql query slides
Haskell 101
Powerful Explain in MySQL 5.6
MySQL understand Indexes
SQL || overview and detailed information about Sql
Optimizing queries MySQL
Go internals (Go Israel Meetup)
Pemrograman Terstruktur 4
Chetan postgresql partitioning
MySQL Optimizer: What’s New in 8.0
Sql
MariaDB Optimizer - further down the rabbit hole
[INSIGHT OUT 2011] B24 effective indexing(tom kyte)
PythonOOP
learn you some erlang - chap0 to chap2
CQL 实现
sql statement
Python Lab Manual
Ad

Similar to MySQL 8.0 NF : Common Table Expressions (CTE) (20)

PPT
PPTX
Set Operators, Derived Tables and CTEs
PPTX
Set operators - derived tables and CTEs
PDF
MySQL 8.0: Common Table Expressions
PDF
MySQL 8.0: Common Table Expressions
PDF
Table partitioning in PostgreSQL + Rails
ODP
Mysql1
PDF
PPT -The MySQL Query optimizer trace .pdf
PPTX
SQL Data Manipulation language and DQL commands
PDF
WORKSHEET SQL SOLVED FOR CLASS XII FINAL
PPTX
Interacting with Oracle Database
PPT
Oracle tips and tricks
PDF
Postgres can do THAT?
PPSX
Row Pattern Matching in Oracle Database 12c
PPT
asdasdasdasdsadasdasdasdasdsadasdasdasdsadsadasd
PDF
dbms lab manual
PPTX
SQL Class Note By Amit Maity PowerPoint Presentation
PPTX
Oraclesql
Set Operators, Derived Tables and CTEs
Set operators - derived tables and CTEs
MySQL 8.0: Common Table Expressions
MySQL 8.0: Common Table Expressions
Table partitioning in PostgreSQL + Rails
Mysql1
PPT -The MySQL Query optimizer trace .pdf
SQL Data Manipulation language and DQL commands
WORKSHEET SQL SOLVED FOR CLASS XII FINAL
Interacting with Oracle Database
Oracle tips and tricks
Postgres can do THAT?
Row Pattern Matching in Oracle Database 12c
asdasdasdasdsadasdasdasdasdsadasdasdasdsadsadasd
dbms lab manual
SQL Class Note By Amit Maity PowerPoint Presentation
Oraclesql
Ad

More from I Goo Lee (20)

PDF
MySQL_Fabric_운영시유의사항
PDF
MySQL Deep dive with FusionIO
PDF
From MSSQL to MySQL
PDF
From MSSQL to MariaDB
PDF
AWS Aurora 100% 활용하기
PDF
Backup automation in KAKAO
PDF
텔레그램을 이용한 양방향 모니터링 시스템 구축
PDF
Federated Engine 실무적용사례
PDF
MySQL 상태 메시지 분석 및 활용
PDF
MySQL 5.7 NF – Optimizer Improvement
PDF
MySQL 5.7 NF – JSON Datatype 활용
PDF
Intro KaKao MRTE (MySQL Realtime Traffic Emulator)
PDF
MS 빅데이터 서비스 및 게임사 PoC 사례 소개
PDF
AWS 환경에서 MySQL Infra 설계하기-2본론
PDF
AWS 환경에서 MySQL Infra 설계하기-1도입부분
PDF
AWS 환경에서 MySQL BMT
PDF
MySQL Slow Query log Monitoring using Beats & ELK
PDF
MySQL Audit using Percona audit plugin and ELK
PDF
PostgreSQL 이야기
PDF
Intro KaKao ADT (Almighty Data Transmitter)
MySQL_Fabric_운영시유의사항
MySQL Deep dive with FusionIO
From MSSQL to MySQL
From MSSQL to MariaDB
AWS Aurora 100% 활용하기
Backup automation in KAKAO
텔레그램을 이용한 양방향 모니터링 시스템 구축
Federated Engine 실무적용사례
MySQL 상태 메시지 분석 및 활용
MySQL 5.7 NF – Optimizer Improvement
MySQL 5.7 NF – JSON Datatype 활용
Intro KaKao MRTE (MySQL Realtime Traffic Emulator)
MS 빅데이터 서비스 및 게임사 PoC 사례 소개
AWS 환경에서 MySQL Infra 설계하기-2본론
AWS 환경에서 MySQL Infra 설계하기-1도입부분
AWS 환경에서 MySQL BMT
MySQL Slow Query log Monitoring using Beats & ELK
MySQL Audit using Percona audit plugin and ELK
PostgreSQL 이야기
Intro KaKao ADT (Almighty Data Transmitter)

Recently uploaded (20)

PPT
tcp ip networks nd ip layering assotred slides
PDF
Best Practices for Testing and Debugging Shopify Third-Party API Integrations...
PDF
💰 𝐔𝐊𝐓𝐈 𝐊𝐄𝐌𝐄𝐍𝐀𝐍𝐆𝐀𝐍 𝐊𝐈𝐏𝐄𝐑𝟒𝐃 𝐇𝐀𝐑𝐈 𝐈𝐍𝐈 𝟐𝟎𝟐𝟓 💰
PPTX
Slides PPTX World Game (s) Eco Economic Epochs.pptx
PDF
Cloud-Scale Log Monitoring _ Datadog.pdf
PPTX
artificial intelligence overview of it and more
PPTX
Introuction about ICD -10 and ICD-11 PPT.pptx
PPTX
522797556-Unit-2-Temperature-measurement-1-1.pptx
PDF
Tenda Login Guide: Access Your Router in 5 Easy Steps
PDF
Exploring VPS Hosting Trends for SMBs in 2025
PPTX
Introduction to Information and Communication Technology
PDF
The New Creative Director: How AI Tools for Social Media Content Creation Are...
DOCX
Unit-3 cyber security network security of internet system
PDF
An introduction to the IFRS (ISSB) Stndards.pdf
PDF
Vigrab.top – Online Tool for Downloading and Converting Social Media Videos a...
PDF
Introduction to the IoT system, how the IoT system works
PPT
Ethics in Information System - Management Information System
PDF
Paper PDF World Game (s) Great Redesign.pdf
PPTX
Power Point - Lesson 3_2.pptx grad school presentation
PPTX
artificialintelligenceai1-copy-210604123353.pptx
tcp ip networks nd ip layering assotred slides
Best Practices for Testing and Debugging Shopify Third-Party API Integrations...
💰 𝐔𝐊𝐓𝐈 𝐊𝐄𝐌𝐄𝐍𝐀𝐍𝐆𝐀𝐍 𝐊𝐈𝐏𝐄𝐑𝟒𝐃 𝐇𝐀𝐑𝐈 𝐈𝐍𝐈 𝟐𝟎𝟐𝟓 💰
Slides PPTX World Game (s) Eco Economic Epochs.pptx
Cloud-Scale Log Monitoring _ Datadog.pdf
artificial intelligence overview of it and more
Introuction about ICD -10 and ICD-11 PPT.pptx
522797556-Unit-2-Temperature-measurement-1-1.pptx
Tenda Login Guide: Access Your Router in 5 Easy Steps
Exploring VPS Hosting Trends for SMBs in 2025
Introduction to Information and Communication Technology
The New Creative Director: How AI Tools for Social Media Content Creation Are...
Unit-3 cyber security network security of internet system
An introduction to the IFRS (ISSB) Stndards.pdf
Vigrab.top – Online Tool for Downloading and Converting Social Media Videos a...
Introduction to the IoT system, how the IoT system works
Ethics in Information System - Management Information System
Paper PDF World Game (s) Great Redesign.pdf
Power Point - Lesson 3_2.pptx grad school presentation
artificialintelligenceai1-copy-210604123353.pptx

MySQL 8.0 NF : Common Table Expressions (CTE)

  • 1. Common Table Expressions By MySQL 8.0 LAB 2017.01.14 (MySQL Power Group) 1
  • 2. 2 Index  Common Table Expression (CTE) 이란?  Non-recursive common table expression  Recursive common table expression  Appendix
  • 3. 3 Common Table Expression  MySQL 8.0 Labs Release 된 New Feature!  기존 파생 테이블은 From절에 subquery 로 표현 SELECT … FROM (subquery) AS drived, t1 …  Common Table Expression(CTE)는 파생테이블과 비슷하지만, From 절 대신 쿼리 블록 앞에 선언! WITH derived AS (subquery) SELECT… FROM derived, t1…  CTE는 subquery가 포함된 SELECT/UPDATE/DELETE에도 사용 가능 WITH derived AS (subquery) DELETE FROM t1 WHERE t1.a IN (SELECT b from derived);
  • 4. 4 EX) SELECT CREATE TABLE t1 ( a INT , b INT ); INSERT INTO t1 VALUES (1,1),(2,2),(3,3); WITH qn AS ( SELECT a+2 AS a, b FROM t1 ) SELECT * FROM qn; Common Table Expression - select
  • 5. 5 Common Table Expression - update EX) UPDATE WITH qn AS ( SELECT a+2 AS a, b FROM t1 ) UPDATE t1, qn SET t1.a=qn.a+10 WHERE t1.a = qn.a; SELECT * FROM t1; self join을 CTE로 작성할 수 있다.
  • 6. 6 Common Table Expression - delete EX) DELETE WITH qn AS ( SELECT a+2 AS a, b FROM t1 ) DELETE t1 FROM t1, qn WHERE t1.a = qn.a; SELECT * FROM t1;
  • 7. 7 Common Table Expression - insert EX) INSERT INSERT INTO t2 WITH qn AS ( SELECT 10*a AS a FROM t1 ) SELECT * FROM qn; SELECT * FROM t2
  • 8. 8 CTE vs 파생테이블 Better readability Can be referenced multiple times Can refer to other CTEs Improved Performance
  • 9. 9 Better readability • 파생테이블 : SELECT * FROM t1 LEFT OUTER JOIN ( SELECT * FROM t2) AS t2 ON t1.id = t2.id LEFT OUTER JOIN ( SELECT * FROM t3) AS t3 ON t1.id = t2.id; • CTE : WITH t2 AS( SELECT * FROM t2 ), t3 AS( SELECT * FROM t3 ) SELECT * FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.id LEFT OUTER JOIN t2 ON t1.id = t3.id;
  • 10. 10 Can be referenced multiple times • 파생테이블 : SELECT * FROM (SELECT ProductID, COUNT(*) FROM Orders GROUP BY ProductID) A INNER JOIN (SELECT ProductID, COUNT(*) FROM Orders GROUP BY ProductID) B ON A.ProductID = B.ProductID; • CTE : WITH CTE AS ( SELECT ProductID, COUNT(*) AS Cnt FROM Orders GROUP BY ProductID ) SELECT * FROM CTE A INNER JOIN CTE B ON A.ProductID = B.ProductID;
  • 11. 11 Can refer to other CTEs • 파생테이블 : SELECT * FROM (SELECT * FROM Products) A, (SELECT * FROM A) B ERROR : 1146 : Table `A` doesn’t exists • CTE : WITH A AS( SELECT * FROM Prouducts) , B AS( SELECT * FROM A) SELECT * FROM A;  products 테이블은 한번만 참조!
  • 12. 12 Chained CTEs WITH cte1(txt) AS ( SELECT "This " ) , cte2(txt) AS ( SELECT CONCAT(cte1.txt,"is a ") FROM cte1) , cte3(txt) AS ( SELECT "nice query" UNION SELECT "query that rocks" UNION SELECT "query") , cte4(txt) AS ( SELECT concat(cte2.txt, cte3.txt) FROM cte2, cte3 ) SELECT MAX(txt), MIN(txt) FROM cte4; MAX(txt) MIN(txt) This is a query that rocks This a nice query 좋은 예는 아니지만, 이렇게도 쓸 수 있습니다. txt This is a nice query This is a query that rocks This is a query
  • 13. 13 ****테스트 데이터 생성*** -- 1~1000 상품 생성 CREATE TABLE Products SELECT @rownum :=@rownum+1 AS ProductID , CAST(RAND()*100000 AS UNSIGNED) AS Price FROM information_schema.columns A , (SELECT @rownum := 0) B LIMIT 1000; -- 1,000,000건 주문 데이터 생성 CREATE TABLE Orders SELECT DATE_ADD('2010-01-01', INTERVAL CAST(RAND()*3000000 AS UNSIGNED) MINUTE) AS OrderDate , CAST(RAND()*1000 AS UNSIGNED) AS ProductID , CAST(RAND()*100000 AS UNSIGNED) FROM information_schema.columns A , information_schema.columns B , information_schema.columns C LIMIT 1000000; ALTER TABLE Products ADD PRIMARY KEY (ProductID); CREATE INDEX Idx_Orders01 ON Orders (OrderDate); CREATE INDEX Idx_Orders02 ON Orders (ProductID); Improved Performance Products ProductID (PK) Price Orders OrderDate ProductID UserID
  • 14. 14 Improved Performance - view CREATE VIEW v_Orders AS SELECT A.ProductID, SUM(B.Price) AS TotPrice, COUNT(*) AS orderCount FROM Orders A INNER JOIN Products B ON A.ProductID = B.ProductID GROUP BY A.ProductID; SELECT * FROM Products A, v_Orders B WHERE A.ProductID = B.ProductID AND A.ProductID = (SELECT MAX(ProductID) FROM v_Orders); ProductID Price ProductID TotPrice orderCount 1000 55523 1000 30537650 550 1 row in set (1.74 sec)  v_Orders를 두 번 사용할 경우입니다.
  • 16. 16 WITH CTE AS( SELECT A.ProductID, SUM(B.Price) AS TotPrice, COUNT(*) AS orderCount FROM Orders A INNER JOIN Products B ON A.ProductID = B.ProductID GROUP BY A.ProductID ) SELECT * FROM Products A , CTE B WHERE A.ProductID = B.ProductID AND A.ProductID = (SELECT MAX(ProductID) FROM CTE); Improved Performance - CTE ProductID Price ProductID TotPrice orderCount 1000 55523 1000 30537650 550 1 row in set (0.70 sec)
  • 19. 19 Recursive 란? def countdown(n): if n == 0: print "Blastoff!" else: print n countdown(n-1); >>> countdown(3) 3 2 1 Blastoff! 함수가 자기 자신을 호출하는 것! Countdown(n) n == 0 종료! n=n-1
  • 20. 20 Recursive CTE WITH RECURSIVE cte AS( SELECT … FROM table_name /* “seed” SELECT */ UNION ALL SELECT … FROM cte, table_name /* “recursive” SELECT */ ) SELECT … FROM cte; • “seed” SELECT를 한 번 실행하여 초기 데이터 하위 집합을 만들고 재귀 SELECT를 반복 실행하여 전체 결과 집합이 얻어 질 때까지 데이터의 하위 집합을 반환함 • 새로운 Row가 생기지 않을 경우 재귀가 중지됨. • 계층 구조 쿼리를 작성하는데 유용 (부모/자식, 부분/하위)
  • 21. 21 Recursive CTE – Example 1 Print 1 to 10 : WITH RECURSIVE num AS ( SELECT 1 AS n  Seed UNION ALL SELECT 1+n FROM num WHERE n < 10  Recursive ) SELECT n FROM num; n 1 2 3 4 5 6 7 8 9 10
  • 22. 22 Fibonacci Numbers : 0과 1로 시작하며, 다음 피보나치 수는 바로 앞의 두 피보나치 수의 합이 된다. WITH RECURSIVE num AS ( SELECT 1 AS n, 1 AS n1, 1 AS n2 UNION ALL SELECT 1+n, n2, n1+n2 FROM num WHERE n < 10 ) SELECT n, n1, n2 FROM num; Recursive CTE – Example 2 n n1 n2 1 1 1 2 1 2 3 2 3 4 3 5 5 5 8 6 8 13 7 13 21 8 21 34 9 34 55 10 55 89
  • 23. 23 Recursive CTE – Example 3 4-digit bit string print (1/3) WITH RECURSIVE digits AS ( SELECT '0' AS d UNION ALL SELECT '1' ), strings AS ( SELECT CAST('' AS CHAR(4)) AS s UNION ALL SELECT CONCAT(strings.s, digits.d) FROM strings, digits WHERE LENGTH(strings.s) < 4 ) SELECT * FROM strings WHERE LENGTH(s)=4;
  • 24. 24 S 0 1 S 0 1 S 0 0 0 1 1 0 1 1 S 0 1 ………. Recursive CTE – Example 3 해당 구문이 없으면 문자 열 크기가 char(1)로 정해 져 버린다. WITH RECURSIVE digits AS ( SELECT '0' AS d UNION ALL SELECT '1' ), strings AS ( SELECT CAST('' AS CHAR(4)) AS s UNION ALL SELECT CONCAT(strings.s, digits.d) FROM strings, digits WHERE LENGTH(strings.s) < 4 ) SELECT * FROM strings WHERE LENGTH(s)=4; 4-digit bit string print (2/3)
  • 25. 25 Recursive CTE – Example 3 4-digit bit string print (3/3) WITH RECURSIVE digits AS ( SELECT '0' AS d UNION ALL SELECT '1' ), strings AS ( SELECT CAST('' AS CHAR(4)) AS s UNION ALL SELECT CONCAT(strings.s, digits.d) FROM strings, digits WHERE LENGTH(strings.s) < 4 ) SELECT * FROM strings WHERE LENGTH(s)=4;
  • 26. 26 Recursive CTE – Example 4 CREATE TABLE MyEmployees ( EmployeeID VARCHAR(100) NOT NULL, EmployeeName NVARCHAR(30) NOT NULL, ManagerID INT NULL, PRIMARY KEY (EmployeeID ) ); INSERT INTO MyEmployees VALUES (1, N'유재석',NULL) ,(273, N'박명수',1) ,(274, N'정준하',1) ,(275, N'하하',273) ,(276, N'양세형',274) ,(285, N'황광희',273) ,(286, N'정형돈',276) ,(16, N'노홍철', 285) ,(23, N'길', 16); 1 유재석 273 박명수 274 정준하 275 하하 16 노홍철 23 길 285 황광희 276 양세형 286 정형돈
  • 27. 27 Recursive CTE – Example 4 WITH RECURSIVE EmployeeOrder AS ( SELECT EmployeeID, EmployeeName, 1 AS LEVEL, EmployeeID AS Path FROM MyEmployees WHERE ManagerID IS NULL UNION ALL SELECT A.EmployeeID, A.EmployeeName, LEVEL + 1, CONCAT(B.Path, ',', A.EmployeeID) FROM MyEmployees A INNER JOIN EmployeeOrder B ON A.ManagerID = B.EmployeeID ) SELECT * FROM EmployeeOrder; 1. 재귀적 CTE 인 EmployeeOrder는 Seed와 Recursive를 정의함 2. Seed는 직급이 가장 높은 (ManagerID is NULL)로 정의함 3. Level은 Tree의 depth이고, Path는 경로를 나타냄 EmplyeeID EmployeeName Level Path 1 유재석 1 1 [Seed]
  • 28. 28 4. Recursive는 Seed 결과 집합에 있는 직원의 직속 하급자를 반환함 Employee 테이블과 EmployeeOrder CTE 간의 조인작업을 통해 수행되며 첫 번째 반복작업은 다음 결과가 Return 됨 Recursive CTE – Example 4 EmplyeeID EmployeeName Level Path 1 유재석 1 1 273 박명수 2 1,273 274 정준하 2 1,274
  • 29. 29 5. Recursive가 반복적으로 활성화되며, 273, 274를 ManagerID로 가지고 있는 결과를 반환함 EmplyeeID EmployeeName Level Path 1 유재석 1 1 273 박명수 2 1,273 274 정준하 2 1,274 275 하하 3 1,273,275 276 양세형 3 1,274,275 285 황광희 3 1,273,258 Recursive CTE – Example 4
  • 30. 30 WITH RECURSIVE EmployeeOrder AS ( SELECT EmployeeID, EmployeeName, 1 AS LEVEL, EmployeeID AS Path FROM MyEmployees WHERE ManagerID IS NULL UNION ALL SELECT A.EmployeeID, A.EmployeeName, LEVEL + 1, CONCAT(B.Path, ',', A.EmployeeID) FROM MyEmployees A INNER JOIN EmployeeOrder B ON A.ManagerID = B.EmployeeID ) SELECT * FROM EmployeeOrder; Recursive CTE – Example 4 EmployeeID EmployeeName Level Path 1 유재석 1 1 273 박명수 2 1,273 274 정준하 2 1,274 275 하하 3 1,273,275 276 양세형 3 1,274,276 285 황광희 3 1,273,285 16 노홍철 4 1,273,285,16 286 정형돈 4 1,274,276,286 23 길 5 1,273,285,16,23
  • 31. 31 Recursive CTE • 계층적 데이터를 조작 및 구현을 쉽게 할 수 있음  회사 계급 구조  메뉴 구조  가족 관계  주소  게시판 등등… • Recursive CTE에 SELECT 절에는 아래 예약어가 포함될 수 없음  GROUP BY  Aggregate function (SUM, MAX….)  ORDER BY  LIMIT  DISTINCT
  • 32. 32 Recursive CTE – Example 4  특정직원(정준하)의 부하를 찾아보자! WITH RECURSIVE EmployeeOrder AS ( SELECT EmployeeID, EmployeeName, 1 AS LEVEL, EmployeeID AS Path FROM MyEmployees WHERE EmployeeID = 274 (정준하) UNION ALL SELECT A.EmployeeID, A.EmployeeName, LEVEL + 1, CONCAT(B.Path, ',', A.EmployeeID) FROM MyEmployees A INNER JOIN EmployeeOrder B ON A.ManagerID = B.EmployeeID ) SELECT * FROM EmployeeOrder EmplyeeID EmployeeName Level Path 274 정준하 1 274 276 양세형 2 274,276 286 정형돈 3 274.276,286
  • 33. 33 Recursive CTE – Example 4  특정직원(정형돈)의 상사를 찾아보자! WITH RECURSIVE EmployeeOrder AS ( SELECT ManagerID, EmployeeName, 1 AS LEVEL FROM MyEmployees WHERE EmployeeID = 286 (정형돈) UNION ALL SELECT A.ManagerID, A.EmployeeName, 1+LEVEL FROM MyEmployees A INNER JOIN EmployeeOrder B ON A.EmployeeID = B.ManagerID ) SELECT * FROM EmployeeOrder ManagerID EmployeeName Level 276 정형돈 1 274 양세형 2 1 정준하 3 NULL 유재석 4  탐색이 역순이기 때문에 path는 별도 Join으로 나타내어야 함
  • 34. 34 Index  Common Table Expression (CTE) 이란?  Non-recursive common table expression  Recursive common table expression  Appendix # Descending Index
  • 35. 35 Descending Indexes  MySQL 8.0 부터는 Descending Index 지원 !! mysql 5.6> CREATE TABLE t1 (a INT, b INT, INDEX a_desc_b_asc (a DESC, b ASC)); Query OK, 0 rows affected (0.47 sec) mysql 5.6> SHOW CREATE TABLE t1G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, KEY `a_desc_b_asc` (`a`,`b`)  Descending 인덱스로 생성이 되지 않는다. ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 1 row in set (0.00 sec) mysql 8.0> CREATE TABLE t1 (a INT, b INT, INDEX a_desc_b_asc (a DESC, b ASC)); Query OK, 0 rows affected (0.47 sec) mysql 8.0 > SHOW CREATE TABLE t1G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, KEY `a_desc_b_asc` (`a` DESC,`b`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 1 row in set (0.00 sec)
  • 36. 36 Descending Indexes Test 환경 (공통) H/W - Amazon EC2 (t2.medium) CPU : 2Core / Memory : 4GB OS - Amazon Linux 비교 DBMS - MySQL 8.0 Labs - MySQL 5.6.29 CREATE TABLE descendingTable ( ID INT DEFAULT NULL, LEVEL INT DEFAULT NULL, KEY (ID DESC, LEVEL ASC) ); INSERT INTO descendingTable SELECT CAST(RAND()*100000 AS UNSIGNED) AS ID , CAST(RAND()*100 AS UNSIGNED) AS LEVEL FROM information_schema.columns A, information_schema.columns B, information_schema.columns C LIMIT 1000000;
  • 37. 37 Descending Indexes - 1 mysql 5.6> SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000; Query OK, 1000 rows affected (0.044 sec) mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- --------------- ------ ------------- ------ ------- ------ ------ ------------- 1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index mysql 8.0> SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000; Query OK, 1000 rows affected (0.042 sec) mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC LIMIT 1000; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- --------------- ------ ------------- ------ ------- ------ ------ ------------- 1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index ID DESC, LEVEL ASC ⇒ ID ASC, LEVEL ASC ID DESC, LEVEL ASC
  • 38. 38 Descending Indexes - 2 mysql 5.6> SELECT * FROM descendingTable ORDER BY ID ASC LIMIT 1000; Query OK, 1000 rows affected (0.042 sec) mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID LIMIT 1000; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- --------------- ------ ------------- ------ ------- ------ ------ ------------- 1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index mysql 8.0> SELECT * FROM descendingTable ORDER BY ID ASC LIMIT 1000; Query OK, 1000 rows affected (0.042 sec) mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID LIMIT 1000; partitions type possible_keys key key_len ref rows filtered Extra ---------- ------ ------------- ------ ------- ------ ------ -------- ---------------------------------- (NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Backward index scan Descending 인덱스가 지원되면서 Backward index scan이라는 연산이 생김 ID DESC, LEVEL ASC ID DESC, LEVEL ASC ⇒ ID ASC, LEVEL ASC
  • 39. 39 Descending Indexes - 3 mysql 5.6> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL ASC LIMIT 1000; Query OK, 1000 rows affected (0.455 sec) mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL LIMIT 1000; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- --------------- ------ ------------- ------ ------- ------ ------ ----------------------------- 1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 998412 Using index; Using filesort mysql 8.0> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL ASC LIMIT 1000; Query OK, 1000 rows affected (0.042 sec) mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL LIMIT 1000; partitions type possible_keys key key_len ref rows filtered Extra ---------- ------ ------------- ------ ------- ------ ------ -------- ------------- (NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; • 정렬 조건이 내림/올림 차순이 혼재해 있을 경우 MySQL 5.6버전에서는 Filesort가 발생되며 그 수행속도 차이는 매우 큼 ID DESC, LEVEL ASC ID DESC, LEVEL ASC ⇒ ID ASC, LEVEL ASC
  • 40. 40 Descending Indexes - 4 mysql 5.6> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000; Query OK, 1000 rows affected (0.457 sec) mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- --------------- ------ ------------- ------ ------- ------ ------ ----------------------------- 1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 998412 Using index; Using filesort mysql 8.0> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000; Query OK, 1000 rows affected (0.042 sec) mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL DESC LIMIT 1000; partitions type possible_keys key key_len ref rows filtered Extra ---------- ------ ------------- ------ ------- ------ ------ -------- ---------------------------------- (NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Backward index scan • MySQL 8.0 에서는 backward index scan을 수행하므로, filesort 없이 빠른 처리가 가능 ID DESC, LEVEL ASC ID DESC, LEVEL ASC ⇒ ID ASC, LEVEL ASC
  • 41. 41 Descending Indexes - 5 mysql 5.6> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000; Query OK, 1000 rows affected (0.044 sec) mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- --------------- ------ ------------- ------ ------- ------ ------ ------------- 1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index mysql 8.0> SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000; Query OK, 1000 rows affected (0.452 sec) mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID DESC, LEVEL DESC LIMIT 1000; partitions type possible_keys key key_len ref rows filtered Extra ---------- ------ ------------- ------ ------- ------ ------ -------- ---------------------------------- (NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Using Filesort • 정의가 되어 있지 않은 정렬을 하므로 MySQL 8.0에서도 filesort가 발생함. 이는 적절한 인덱스를 생성하여 filesort를 방지할 수 있음 ex) (ID DESC, LEVEL DESC) or (ID ASC, LEVEL ASC) ID DESC, LEVEL ASC ID DESC, LEVEL ASC ⇒ ID ASC, LEVEL ASC
  • 42. 42 Descending Indexes - 6 mysql 5.6> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000; Query OK, 1000 rows affected (0.457 sec) mysql 5.6> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- --------------- ------ ------------- ------ ------- ------ ------ ------------- 1 SIMPLE descendingTable index (NULL) ID 10 (NULL) 1000 Using index mysql 8.0> SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000; Query OK, 1000 rows affected (0.042 sec) mysql 8.0> EXPLAIN SELECT * FROM descendingTable ORDER BY ID ASC, LEVEL ASC LIMIT 1000; partitions type possible_keys key key_len ref rows filtered Extra ---------- ------ ------------- ------ ------- ------ ------ -------- ---------------------------------- (NULL) index (NULL) ID 10 (NULL) 1000 100.00 Using index; Using Filesort ID DESC, LEVEL ASC ID DESC, LEVEL ASC ⇒ ID ASC, LEVEL ASC
  • 43. 43 • MySQL 5.7에서는 query3/4 같은 쿼리의 성능을 향상 시킬 수가 없었으나, MySQL 8.0부터는 Descending Index 를 통해 성능 향상을 할 수 있음 결론
  • 44. 44