KQL์ด๋ ๋ฌด์์ธ๊ฐ?
KQL(Kusto Query Language)์ Azure Data Explorer(ADX)์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ธฐ ์ํ ์ ์ฉ ์ฟผ๋ฆฌ ์ธ์ด์ด๋ค.
Micorsoft๊ฐ ๋ง๋ค์๊ณ , ๋๊ท๋ชจ ๋ก๊ทธ ๋ฐ์ดํฐ์ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ๊ฒ์·์ง๊ณํ๋๋ฐ ์ต์ ํ๋์ด ์๋ค.
๐ก ๋น์
SQL์ด MSSQL์์ ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด๋ ์ธ์ด๋ผ๋ฉด, KQL์ ADX์์ ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด๋ ์ธ์ด์ด๋ค.
๋ ๋ค "๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ์ธ์ด"๋ผ๋ ์ ์ ๊ฐ์ง๋ง, ๋ฌธ๋ฒ ๊ตฌ์กฐ๊ฐ ์์ ํ ๋ค๋ฅด๋ค.
SQL๊ณผ KQL์ ๊ตฌ์กฐ์ ์ฐจ์ด
SQL์ "๋ด๊ฐ ์ํ๋ ๊ฒ์ ์ ์ธ"ํ๋ ๊ตฌ์กฐ์ด๋ค.
SELECT, FROM, WHERE์ ํ๊บผ๋ฒ์ ์ ์ด์ ์ ์ถํ๋ ์ฃผ๋ฌธ์ ๋ฐฉ์์ด๋ค.
๋ฐ๋ฉด KQL์ "๋ฐ์ดํฐ๋ฅผ ํ์ดํ๋ผ์ธ์ผ๋ก ํ๋ ค๋ณด๋ด๋" ๊ตฌ์กฐ์ด๋ค.
ํ์ดํ( | )๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ํ ๋จ๊ณ์ฉ ๊ฐ๊ณตํ๋ฉด์ ์๋๋ก ํ๋ ค๋ณด๋ธ๋ค.
-- SQL
SELECT name, age
FROM users
WHERE age > 20
ORDER BY age
-- KQL
users
| where age > 20
| project name, age
| sort by age
๐ก ๋น์
SQL์ ์ฃผ๋ฌธ์๋ฅผ ํ ์ฅ ์์ฑํด์ ํ๊บผ๋ฒ์ ๋ด๋ฏธ๋ ๋๋์ด๊ณ , KQL์ ๊ณต์ฅ ์ปจ๋ฒ ์ด์ด ๋ฒจํธ์ฒ๋ผ ๋ฐ์ดํฐ๋ฅผ ์์์ ์ฌ๋ ค๋๊ณ ํ ๋จ๊ณ์ฉ ๊ฐ๊ณตํ๋ฉด์ ์๋๋ก ํ๋ ค๋ณด๋ด๋ ๋๋์ด๋ค.
| ๊ตฌ๋ถ | SQL (MSSQL) | KQL (ADX) |
| ์ฝ๋ ์์ | SELECT → FROM → WHERE (์คํ ์์์ ๋ค๋ฆ) | ์์์ ์๋๋ก ์์๋๋ก (์ง๊ด์ ) |
| ๊ตฌ๋ถ์ | ์์ (์ ํค์๋๋ก ๊ตฌ๋ถ) | ํ์ดํ | ๋ก ๋จ๊ณ ๊ตฌ๋ถ |
| ์ปฌ๋ผ ์ ํ | SELECT | project |
| ํํฐ | WHERE | where |
| ์ ๋ ฌ | ORDER BY | osrt by |
| ์ฃผ์ ์ฉ๋ | ๊ด๊ณํ DB ์กฐํ/์กฐ์ (CRUD) | ๋๊ท๋ชจ ๋ก๊ทธ / ์๊ณ์ด ๋ฐ์ดํฐ ๋ถ์ |
์ ADX์์ SQL ๋์ KQL์ ์ธ๊น?
ADX๊ฐ ๋ค๋ฃจ๋ ๋ฐ์ดํฐ๋ ๋๋ถ๋ถ ๋ก๊ทธ ๋ฐ์ดํฐ์ด๋ค.
๋ก๊ทธ๋ ์์ด ์ด๋ง์ด๋งํ๊ณ , ์๊ฐ ์์๋๋ก ์์ด๋ฉฐ, ๋๋ถ๋ถ ์ฝ๊ธฐ ์ ์ฉ(INSERT๋ง ์๊ณ UPDATE/DELETE๊ฐ ๊ฑฐ์ ์์)์ด๋ค.
KQL์ ์ด๋ฐ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ๊ฒ์ํ๊ณ ์ง๊ณํ๋ ๋ฐ ์ต์ ํ๋์ด ์๋ค.
| ๊ด์ | SQL (MSSQL) | KQL (ADX) |
| ์ค๊ณ ๋ชฉ์ | ์ ํ ๋ฐ์ดํฐ ๊ด๋ฆฌ (CRUD ๋ชจ๋) | ๋๊ท๋ชจ ๋ก๊ทธ / ์๊ณ์ด ๋ฐ์ดํฐ ์ฝ๊ธฐ ํนํ |
| ๋ฐ์ดํฐ ์ ์ฅ | ํ(Row) ๊ธฐ๋ฐ ์ ์ฅ | ์ด(Column) ๊ธฐ๋ฐ ์ ์ฅ → ์ง๊ณ์ ์ ๋ฆฌ |
| ์์ต ๊ฑด ์ง๊ณ | ๋๋ ค์ง ์ ์์ | ์์ด ๋ด ๊ฐ๋ฅ |
| UPDATE / DELETE | โ ์์ ๋กญ๊ฒ ๊ฐ๋ฅ | โ ๊ฑฐ์ ๋ถ๊ฐ (๋ก๊ทธ๋ ์๊ธฐ๋ง ํ๋๊น OK) |
โ ์ฐธ๊ณ
์ด(Column) ๊ธฐ๋ฐ ์ ์ฅ์ด ์ ๋น ๋ฅผ๊น?
"์ค๋ ์๋ฌ ๋ก๊ทธ๊ฐ ๋ช ๊ฑด์ด์ผ?" ๊ฐ์ ์ง๋ฌธ์์, ํ ๊ธฐ๋ฐ(SQL)์ ๋ชจ๋ ํ์ ์ฝ์ผ๋ฉด์ ํด๋น ์ปฌ๋ผ์ ํ์ธํ๋ค.
์ด ๊ธฐ๋ฐ(KQL/ADX)์ ํ์ํ ์ปฌ๋ผ๋ง ์ญ ์ฝ๊ณ ๋๋จธ์ง๋ ์์ ์๋ณธ๋ค.
๋ฐ์ดํฐ๊ฐ ํด์๋ก ์ฐจ์ด๊ฐ ๊ทน์ ์ด๋ค.
๐ก ํ ์ค ์ ๋ฆฌ : SQL์ ๋ง๋ฅ ๋๊ตฌ(์ค์์ค ์๋ฏธ ๋์ดํ), KQL์ ๋ก๊ทธ ๋ถ์ ์ ์ฉ ๊ณ ์ฑ๋ฅ ๋๊ตฌ. ์ฉ๋์ ๋ง๊ฒ ์ฐ๋ ๊ฒ!
KQL์ ํต์ฌ ์๋ฆฌ - ์ปจ๋ฒ ์ด์ด ๋ฒจํธ ๊ตฌ์กฐ
KQL ๋ฌธ๋ฒ์ ๋ฐฐ์ฐ๊ธฐ ์ ์, ๋ชจ๋ KQL ์ฟผ๋ฆฌ๊ฐ ๋ฐ๋ฅด๋ ํ๋์ ์๋ฆฌ๋ฅผ ๋จผ์ ์ดํดํด์ผ ํ๋ค.
๐ก ๋น์
KQL์ ์ปจ๋ฒ ์ด์ด ๋ฒจํธ ๊ตฌ์กฐ์ด๋ค.
๋ฐ์ดํฐ๋ฅผ ๋งจ ์์ ์ฌ๋ ค๋๊ณ , ํ์ดํ( | )๋ฅผ ํตํด ํ ๋จ๊ณ์ฉ ๊ฐ๊ณตํ๋ฉด์ ์๋๋ก ํ๋ ค๋ณด๋ธ๋ค.
์์์ ์๋๋ก ์ฝ์ผ๋ฉด ๊ทธ๋๋ก ์คํ ์์!

SQL๊ณผ ๋ฌ๋ฆฌ ์ฝ๋ ์์ = ์คํ ์์์ด๊ธฐ ๋๋ฌธ์ ํจ์ฌ ์ง๊ด์ ์ด๋ค.
์ด ์๋ฆฌ๋ง ๊ธฐ์ตํ๋ฉด ์ด๋ค KQL ์ฟผ๋ฆฌ๋ ์์์ ์๋๋ก ์ฝ์ผ๋ฉด ๋๋ค.
๊ธฐ์ด ๋ฌธ๋ฒ - ๊ธฐ๋ณธ ์กฐํ
ํ ์ด๋ธ ์กฐํ
ํ
์ด๋ธ ์ด๋ฆ๋ง ์ฐ๋ฉด ์ ์ฒด ๋ฐ์ดํฐ๊ฐ ์กฐํ๋๋ค.
SQL์ SELECT * FROM ๊ณผ ๋์ผํ๋ค.
-- SQL
SELECT *
FROM StormEvents
-- KQL
StormEvents
where - ํํฐ๋ง
์กฐ๊ฑด์ ๋ง๋ ํ๋ง ๊ฑธ๋ฌ๋ธ๋ค.
-- SQL
SELECT *
FROM StormEvents
WHERE State = 'TEXAS'
-- KQL
StromEvents
| where State == "TEXAS"
| ์ฐ์ฐ์ | ์๋ฏธ | ์ฃผ์์ฌํญ |
| = | ๊ฐ๋ค | SQL์ =, KQL์ == |
| ≠ | ๊ฐ์ง ์๋ค | |
| >, <, ≤, ≥ | ์ซ์ ๋น๊ต | SQL๊ณผ ๋์ผ |
| and / or | ์กฐ๊ฑด ์กฐํฉ | SQL์ AND, OR๊ณผ ๋์ผ |
| ๋ฌธ์์ด ๋ฐ์ดํ | ํฐ๋ฐ์ดํ " " | SQL์ ์์๋ฐ์ดํ ' ', KQL์ ํฐ๋ฐ์ดํ๊ฐ ๊ธฐ๋ณธ |
์ฌ๋ฌ ์กฐ๊ฑด์ ์กฐํฉํ ๋๋ ํ ์ค์ and / or๋ก ์ฐ๊ฑฐ๋, where๋ฅผ ์ฌ๋ฌ ์ค๋ก ๋๋ ๋ ๋๋ค.
-- ํ ์ค์ ์์ฑ
StormsEvents
| where State == "TEXAS" and EventType == "Flood"
-- ์ฌ๋ฌ ์ค๋ก ๋ถ๋ฆฌ (๊ฐ๋
์ฑ ์ข์)
StormEvents
| where State == "TEXAS"
| where EventType == "Flood"
project - ์ปฌ๋ผ ์ ํ
๋ณด๊ณ ์ถ์ ์ปฌ๋ผ๋ง ๊ณจ๋ผ์ ๊ฒฐ๊ณผ์ ํ์ํ๋ค.
-- SQL
SELECT EventType, StartTime
FROM StormEvents
-- KQL
StormEvents
| project EventType, StartTime
| ๋ช ๋ น์ด | ์ญํ | ์ค๋ช |
| project | ์ง์ ์ปฌ๋ผ๋ง ํ์ | ๋๋จธ์ง ์ปฌ๋ผ์ ๋ชจ๋ ์ ๊ฑฐ๋จ |
| project-away | ์ง์ ์ปฌ๋ผ๋ง ์ ์ธ | ๋๋จธ์ง ์ปฌ๋ผ์ ์ ๋ถ ์ ์ง |
| project-rename | ์ปฌ๋ผ ์ด๋ฆ ๋ณ๊ฒฝ | ๊ธฐ์กด ๊ตฌ์กฐ ์ ์งํ๋ฉด์ ์ด๋ฆ๋ง ๋ฐ๊ฟ |
| extend | ์ ์ปฌ๋ผ ์ถ๊ฐ | ๊ธฐ์กด ์ปฌ๋ผ ์ ์ง + ์ ์ปฌ๋ผ ์ถ๊ฐ |
extend๋ ํนํ ์์ฃผ ์ฐ์ด๋๋ฐ, SQL์ SELECT *, ๊ณ์ฐ์ AS ๋ณ๋ช ๊ณผ ๊ฐ์ ์ญํ ์ด๋ค.
StromEvents
| extend DamageTotal = DamageProperty + DamageCrops
sort by - ์ ๋ ฌ
-- SQL
SELECT *
FROM StormEvents
ORDER BY DamageProperty DESC
-- KQL
StormEvents
| sort by DamageProperty desc
take / limit - ๊ฐ์ ์ ํ
SQL์ SELECT TOP N ๊ณผ ๋์ผํ๋ค.
take์ limit์ ์์ ํ ๊ฐ์ ๋์์ด๋ค.
-- SQL
SELECT TOP 10 *
FROM StormEvents
-- KQL
StormEvents
| take 10
summarize - ์ง๊ณ (๊ฐ์ฅ ์ค์)
KQL์ ๊ฝ์ด๋ค.
SQL์ GROUP BY + ์ง๊ณ ํจ์์ ๊ฐ์ ์ญํ ์ธ๋ฐ, ๋ฌธ๋ฒ์ด ๋ ๊ฐ๊ฒฐํ๋ค.
-- SQL
SELECT State
, COUNT(*)
FROM StormEvents
GROUP BY State
-- KQL
StormEvents
| summarize count() by State
| KQL ํจ์ | SQL ๋์ | ์ค๋ช |
| count() | COUNT(*) | ํ ์ |
| sum(col) | SUM(col) | ํฉ๊ณ |
| avg(col) | AVG(col) | ํ๊ท |
| min(col) / max(col) | MIN / MAX | ์ต์๊ฐ / ์ต๋๊ฐ |
| dcount(col) | COUNT(DISTINCT col) | ๊ณ ์ ๊ฐ ์ |
| countif(col) | ์์ (CSAE WHEN ํ์) | ์กฐ๊ฑด์ ๋ง๋ ํ๋ง ์นด์ดํธ |
countif๋ SQL์๋ ์๋ KQL๋ง์ ํธ๋ฆฌํ ํจ์์ด๋ค.
SQL์์ SUM(CASE WHEN ... THEN 1 ELSE 0 END) ๋ก ์จ์ผ ํ๋ ๊ฒ์ ํ ๋จ์ด๋ก ํด๊ฒฐํ๋ค.
StormEvents
| summarize
TotalEvents = count(),
FloodEvents = countif(EventType == "Flood")
by State
์๊ฐ ๊ด๋ จ - ๋ก๊ทธ ๋ถ์์ ํต์ฌ
๋ก๊ทธ ๋ฐ์ดํฐ์์ ์๊ฐ ๋ค๋ฃจ๋ ์ผ์ ํ์์ด๋ค.
KQL์ ์๊ฐ ์ฒ๋ฆฌ๊ฐ ํนํ ๊ฐ๋ ฅํ๋ค.
-- SQL
SELECT *
FROM StormEvents
WHERE StartTime > DATEADD(DAY, -7, GETDATE())
-- KQL
StormEvents
| where StartTime > ago(7d)
| ์๊ฐ ํํ | ์๋ฏธ |
| ago(1h) | 1์๊ฐ ์ |
| ago(30m) | 30๋ถ ์ |
| ago(7d) | 7์ผ ์ |
bin( ) ํจ์๋ฅผ ์ฐ๋ฉด ์๊ฐ ๋จ์๋ก ์ง๊ณํ ์ ์๋ค.
SQL์์ ๋ ์ง๋ฅผ ์๋ผ์ GROUP BY ํ๋ ค๋ฉด CAST๋ CONVERT๊ฐ ํ์ํ์ง๋ง, KQL์ bin( ) ํ๋๋ฉด ๋์ด๋ค!
์ค๊ธ ๋ฌธ๋ฒ - ๋ณ์, ๋ฒ์, ํ์
let - ๋ณ์ ์ ์ธ
KQL์์ ๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ ๋ฌธ๋ฒ ์ค ํ๋์ด๋ค.
๊ฐ์ด๋ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์ ์ด๋ฆ์ ๋ถ์ฌ์ ์ฌ์ฌ์ฉํ ์ ์๋ค.
๐ก ๋น์
์๋ฆฌ ์์ ์ ์ ์ฌ๋ฃ๋ฅผ ๋ฏธ๋ฆฌ ์์งํด์ ๊ทธ๋ฆ์ ๋ด์๋๋ ๊ฒ์ด๋ค.
์ํ๋ ์ฌ๊ธฐ, ๋ง๋์ ์ ๊ธฐ - ๋ฏธ๋ฆฌ ์ค๋นํด๋์ผ๋ฉด ๋ณธ ์๋ฆฌ์์ ๋ฐ๋ก ๊บผ๋ด ์ธ ์ ์๋ค.
-- ๋จ์ ๊ฐ ์ ์ฅ
let targetDate = datetime('2024-06-01');
let maxCount = 100;
-- ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณ์์ ์ ์ฅ (๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ!)
let errorLogs =
AppLogs
| where Level == "Error"
| where Time > ago(1d);
errorLogs
| summarize count() by ServiceName
โ ๏ธ ์ฃผ์
let ๋ฌธ์ ๋ฐ๋์ ์ธ๋ฏธ์ฝ๋ก ( ; )์ผ๋ก ๋๋์ผ ํ๋ค.
์ ๋ถ์ด๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
โ ์ฐธ๊ณ
SQL์ CTE( WITH ๋ฌธ )์ ๊ฐ์ฅ ๋น์ทํ์ง๋ง, CTE๋ ๋ฐ๋ก ๋ค์ SELECT์์๋ง ์ธ ์ ์๋ ๋ฐ๋ฉด let ์ ์ฌ๋ฌ ๋ฒ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
"CTE์ ํธ๋ฆฌํจ + ์์ ํ ์ด๋ธ์ ์ฌ์ฌ์ฉ์ฑ" ์ ํฉ์น ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.
datatable - ์์ ํ ์ด๋ธ ๋ง๋ค๊ธฐ
DB์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ์์์ ์ง์ ๋ง๋ค์ด ์ธ ์ ์๋ค.
let targets = datatable (Deviced:string) [
"SRV-01",
"SRV-02",
"SRV-03"
];
in - ๋ชฉ๋ก ํฌํจ ํํฐ
-- ์ง์ ๋ชฉ๋ก ์ง์
AppLogs
| where ServiceName in ("Auth", "Payment")
-- ๋ณ์(์๋ธ์ฟผ๋ฆฌ)์ ํจ๊ป ์ฌ์ฉ
AppLogs
| where Deviced in (targets | project DeviceId)
-- ๋ฐ๋ - ํฌํจ๋์ง ์๋ ๊ฒ
AppLogs
| where Servicename !in ("Auth", "Payment")
between - ๋ฒ์ ํํฐ
AppLogs
| where Time between (datetime('2024-06-01') .. datetime('2024-06-30'))
-- ์ซ์์๋ ์ฌ์ฉ ๊ฐ๋ฅ
| where DamageProperty between (100 .. 500)
โ ํฌ์ธํธ
between ๋ฌธ๋ฒ์ ๊ดํธ ( ) ์ ์ ๋ ๊ฐ .. ๋ฅผ ํจ๊ป ์จ์ผ ํ๋ค.
between (A .. B) → A ์ด์ B ์ดํ.
ํ์ ๋ณํ ํจ์
KQL์ ๋ฐ์ดํฐ ํ์
์ ๋ฏผ๊ฐํ๋ค.
JSON์์ ๊บผ๋ธ ๊ฐ์ dynamic ํ์
์ด๋ผ ๋น๊ตํ๋ ค๋ฉด ๋ณํ์ด ํ์ํ๋ค.
| KQL ํจ์ | SQL ๋์ | ์ญํ |
| tostring(๊ฐ) | CAST(๊ฐ AS NVARCHAR) | ๋ฌธ์์ด๋ก ๋ณํ |
| toint(๊ฐ) | CAST(๊ฐ AS INT) | ์ ์๋ก ๋ณํ |
| tolong(๊ฐ) | CAST(๊ฐ AS BIGINT) | ํฐ ์ ์๋ก ๋ณํ |
| todouble(๊ฐ) | CAST(๊ฐ AS FLOAT) | ์ค์๋ก ๋ณํ |
| todatetime(๊ฐ) | CAST(๊ฐ AS DATETIME) | ๋ ์ง๋ก ๋ณํ |
๋ ์ง / ์๊ฐ ํจ์
| KQL ํจ์ | SQL ๋์ | ์ญํ |
| datetime_add('hour', 9, dt) | DATEADD(HOUR, 9 dt) | ๋ ์ง์ ์๊ฐ ๋ํ๊ธฐ |
| endofday(dt) | ์ง์ ๋์ ์์ | ํด๋น ๋ ์ง์ 23:59:59 ๋ฐํ |
| startofday(dt) | ์ง์ ๋์ ์์ | ํด๋น ๋ ์ง์ 00:00:00 ๋ฐํ |
| startofmonth(dt) | ์ง์ ๋์ ์์ | ํด๋น ์์ 1์ผ 00:00:00 |
| format_datetime(dt, 'yyyy-MM-dd') | FORMAT(dt, 'yyyy-MM-dd') | ์ํ๋ ํ์์ผ๋ก ์ถ๋ ฅ |
์ค๊ธ ๋ฌธ๋ฒ - arg_max, union, join
arg_max - ๊ทธ๋ฃน๋ณ ์ต์ ํ ๊ฐ์ ธ์ค๊ธฐ
KQL์์ ๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ฉด์๋ SQL์์๋ ๊ฝค ๋ฒ๊ฑฐ๋ก์ด ์์
์ด๋ค.
"๊ฐ ๊ทธ๋ฃน์์ ํน์ ์ปฌ๋ผ์ด ๊ฐ์ฅ ํฐ(์ต์ ์ธ) ํ์ 1๊ฑด๋ง ๊ฐ์ ธ์"๋ผ๋ ์๋ฏธ๋ค.
๐ก ๋น์
ํ์ 30๋ช ์ ์ํ ๊ธฐ๋ก์ด ์ฌ๋ฌ ๊ฑด์ฉ ์์ ๋, "๊ฐ ํ์์ ๊ฐ์ฅ ์ต๊ทผ ์ํ ๊ฒฐ๊ณผ๋ง ๊ฐ์ ธ์"๋ผ๋ ์์ฒญ์ ํ ์ค๋ก ์ฒ๋ฆฌํ๋ค.
-- SQL
SELECT *
FROM (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY UserId, ORDER BY Time DESC) AS rn
FROM AppLogs
) AS t
WHERE rn = 1
-- KQL
AppLogs
| summarize arg_max(Time, *) by UserId
| ํจ์ | ์๋ฏธ | ์ฉ๋ |
| arg_max(Time, *) | Time์ด ๊ฐ์ฅ ํฐ(์ต์ ) ํ์ ๋ชจ๋ ์ปฌ๋ผ | ์ต์ ์ํ ์กฐํ |
| arg_min(Time, *) | Time์ด ๊ฐ์ฅ ์์(์ต์ด) ํ์ ๋ชจ๋ ์ปฌ๋ผ | ์ต์ด ๊ธฐ๋ก ์กฐํ |
union - ๋ ๊ฒฐ๊ณผ ํฉ์น๊ธฐ
SQL์ UNION ALL ๊ณผ ๋์ผํ๋ค.
๋ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ํ๋๋ก ํฉ์น๋ค.
๐ก ๋น์
๋ ๊ฐ์ ์ ์์ ๋ด๊ธด ์์์ ํ๋์ ํฐ ์ ์์ ํฉ์น๋ ๊ฒ์ด๋ค.
let morningLogs = AppLogs | where Time between (sDate .. noon);
let eveningLogs = AppLogs | where Time between (noon .. eDate);
morningLogs
| union eveningLogs
| summarize count() by Level
join - ๋ ํ ์ด๋ธ ์ฐ๊ฒฐํ๊ธฐ
Users
| join kind-inner Purchase on UserId
| KQL | SQL ๋์ | ์ค๋ช |
| kind=inner | INNER JOIN | ์์ชฝ ๋ชจ๋ ์๋ ๊ฒ๋ง |
| kind=leftouter | LEFT JOIN | ์ผ์ชฝ ์ ๋ถ + ์ค๋ฅธ์ชฝ ๋งค์นญ |
| kind=rightouter | RIGHT JOIN | ์ค๋ฅธ์ชฝ ์ ๋ถ + ์ผ์ชฝ ๋งค์นญ |
| kind=fullouter | FULL OUTER JOIN | ์์ชฝ ์ ๋ถ |
| kind=leftnanti | ์ง์ ๋์ ์์ | โญ ์ผ์ชฝ์๋ง ์๊ณ ์ค๋ฅธ์ชฝ์๋ ์๋ ๊ฒ |
| kind=leftsemi | ์ง์ ๋์ ์์ | ์ผ์ชฝ ์ค์์ ์ค๋ฅธ์ชฝ์ ์๋ ๊ฒ๋ง |
leftanti - ํต์ฌ ์กฐ์ธ ํจํด
๐ก ๋น์
"A ๋ฐ ๋ช ๋จ์๋ ์๋๋ฐ B ๋ฐ ๋ช ๋จ์๋ ์๋ ํ์๋ง ์ฐพ์์ค."๋ผ๋ ์์ฒญ์ด๋ค.
-- SQL
SELECT *
FROM anyRange AS a
WHERE NOT EXISTS (
SELECT 1
FROM inRange AS b
WHERE b.DeviceId = a.DeviceId
)
-- KQL
anyRange
| join kind=leftanti inRange on DeviceId
โ ํฌ์ธํธ
์ค๋ฌด ํ์ฉ ํจํด : "์ค๋ ๋ก๊ทธ๊ฐ ์์ผ๋ฉด ๊ทธ๊ฒ, ์์ผ๋ฉด ๊ณผ๊ฑฐ ์ต์ ๋ก๊ทธ"๋ฅผ ๊ฐ์ ธ์ค๋ ์ ๋ต์์ union + leftanti๊ฐ ํจ๊ป ์ฐ์ธ๋ค.
๋ชจ๋ ๋์์ ์ต์ ๋ฐ์ดํฐ๋ฅผ ๋น ์ง์์ด ํ๋ณดํ๋ ํต์ฌ ํจํด์ด๋ค.
let lastest_rows = inRange
| union (anyRange | join kind leftanti inRange on DeviceId);
-- inRange : ์ค๋ ๋ก๊ทธ ์๋ ๋์
-- anyRange leftanti inRange : ์ค๋ ๋ก๊ทธ ์๋ ๋์์ ๊ณผ๊ฑฐ ์ต์
-- union : ๋์ ํฉ์ณ์ ๋ชจ๋ ๋์ ํ๋ณด!
๊ณ ๊ธ ๋ฌธ๋ฒ - ๋์ ํ์ ๊ณผ mv-expand
๋์ ํ์ (Dynamic Type) - JSON ๋ฐ์ดํฐ ์ ๊ทผ
ADX์ ๋ก๊ทธ ๋ฐ์ดํฐ๋ ํ ์ปฌ๋ผ์ JSON์ด ํต์งธ๋ก ๋ค์ด์๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
KQL์์๋ ์ด๋ฅผ dynamic ํ์
์ด๋ผ ๋ถ๋ฅด๋ฉฐ, ์ ( . )์ผ๋ก ๋ด๋ถ์ ์ ๊ทผํ๋ค.
๐ก ๋น์
MSSQL์์๋ ๋ฐ์ดํฐ๊ฐ ์์ ํ์ฒ๋ผ ๊น๋ํ๊ฒ ์ปฌ๋ผ๋ณ๋ก ์ ์ฅ๋๋ค.
ํ์ง๋ง ADX์ ๋ก๊ทธ ๋ฐ์ดํฐ๋ ํ ์นธ ์์ ํ๋ฐฐ ์์(JSON)๊ฐ ํต์งธ๋ก ๋ค์ด์๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
KQL์ ๊ทธ ์์๋ฅผ ์ ( . )๋ง ์ฐ์ผ๋ฉด ์ด ์ ์๋ค.
{
"Device": {
"Id": "SRV-01",
"Name": "Server-A01"
},
"Metrics": [
{
"MetircType": "CPU",
"Value": 85
},
{
"MetricType": "Memory",
"Value": 72
},
{
"MetricType": "Disk",
"Value": 60
}
]
}
| ์ํฉ | ํด๊ฒฐ์ฑ |
| JSON์์ ๊บผ๋ธ ๊ฐ์ dynamic ํ์ | tostring(), toint() ๋ฑ์ผ๋ก ๋ณํ ํ์ |
| ํค์ ํน์๋ฌธ์/๊ณต๋ฐฑ์ด ์์ ๋ | Data["server-info"] ๋๊ดํธ ํ๊ธฐ๋ฒ ์ฌ์ฉ |
| ์กด์ฌํ์ง ์๋ ํค์ ์ ๊ทผํ๋ฉด | ์๋ฌ ์์ด null ๋ฐํ (์์ ํจ) |
mv-expand - ๋ฐฐ์ด์ ํ์ผ๋ก ํผ์น๊ธฐ
๐ก ๋น์
ํ๋ฐฐ ์์(JSON) ์์ ์ฌ๋ฌ ๊ฐ์ ์์ ์ํ(๋ฐฐ์ด)์ด ํจ๊ป ํฌ์ฅ๋์ด ์์ ๋, ์ํ ํ๋ํ๋๋ฅผ ๊บผ๋ด์ ๊ฐ๊ฐ ๋ณ๋์ ํ์ผ๋ก ๋์ดํ๋ ์์ ์ด๋ค.

latest_rows
| mv-expand Data_Metrics = Data.Metrics
| project
DeviceId = DeviceId,
MetricType = tostring(Data_Metrics.MetricType),
Value = tostring(Data_Metrics.Value)
โ ๏ธ ์ฃผ์
ํ์ด ํฌ๊ฒ ๋์ด๋จ : ๋ฐฐ์ด ์์ ์๋งํผ ํ์ด ๊ณฑํด์ง๋ค.
1๋ง ํ์ ๊ฐ 10๊ฐ์ฉ์ด๋ฉด → 10๋งํ. ๋ํ ๋น ๋ฐฐ์ด[ ] ์ ํด๋น ์ด์ด ๊ฒฐ๊ณผ์์ ์ฌ๋ผ์ง๋ฏ๋ก ์ฃผ์ํด์ผ ํ๋ค.
์ค์ ์ฟผ๋ฆฌ - ์ ์ฒด ํ๋ฆ ๋ถ์

SQL ↔ KQL ์นํธ์ํธ
SQL์ ์๋ ์ํ์์ KQL์ ๋น ๋ฅด๊ฒ ์ฐพ์๋ณผ ์ ์๋๋ก ์ ๋ฆฌํ ํ
| ํ๊ณ ์ถ์ ๊ฒ | SQL (MSSQL) | KQL (ADX) |
| ์ ์ฒด ์กฐํ | SELECT * FROM T | T |
| ์กฐ๊ฑด ํํฐ | WHERE col = 'a' | | where col = "a" |
| ์ปฌ๋ผ ์ ํ | SELECT a, b | | project a, b |
| ์ ์ปฌ๋ผ ์ถ๊ฐ | SELECT *, a+b AS c | | extend c = a + b |
| ์ ๋ ฌ | ORDER BY a DESC | | sort by a desc |
| ๊ฐ์ ์ ํ | SELECT TOP 10 | | take 10 |
| ์ง๊ณ | GROUP BY + COUNT(*) | | summarize count() by col |
| ๊ณ ์ ๊ฐ ์ | COUNT(DISTINCT col) | dcount(col) |
| ์กฐ๊ฑด๋ถ ์นด์ดํธ | SUM(CASE WHEN ...) | countif(์กฐ๊ฑด) |
| ์ต๊ทผ N์ผ | DATEADD(DAY, -7, GETDATE()) | ago(7d) |
| ์๊ฐ ๋จ์ ์ง๊ณ | CAST + GROUP BY | bin(col, 1h) |
| ๋ณ์ ์ ์ธ | DECLARE @v / CTE | let v = ...; |
| ๊ทธ๋ฃน๋ณ ์ต์ ํ | ROW_NUMBER() OVER(...) | arg_max(Time, *) by col |
| JSON ์ ๊ทผ | JSON_VALUE(col, '$.key') | col.key |
| ๋ฐฐ์ด ํผ์น๊ธฐ | CROSS APPLY OPENJSON | mv-expand col |
| ๊ฒฐ๊ณผ ํฉ์น๊ธฐ | UNION ALL | union |
| ์๋ ๊ฒ๋ง ํํฐ | NOT EXISTS / LEFT JOIN + IS NULL | join kind-leftanti |
References
| ์ฃผ์ | ๋ฌธ์ | ๋งํฌ |
| KQL ์ ์ฒด ๋ ํผ๋ฐ์ค | Kusto Query Language ๊ฐ์ | https://learn.microsoft.com/ko-kr/kusto/query/?view=microsoft-fabric |
| KQL ํํ ๋ฆฌ์ผ | Kusto ์ฟผ๋ฆฌ ์์ต์ | https://learn.microsoft.com/ko-kr/kusto/query/tutorials/learn-common-operators?view=microsoft-fabric |
| SQL → KQL ๋ณํ | SQL์์ Kusto๋ก์ ์นํธ ์ํธ | https://learn.microsoft.com/ko-kr/kusto/query/sql-cheat-sheet?view=microsoft-fabric |
| summarize ์ฐ์ฐ์ | summarize ๊ณต์ ๋ฌธ์ | https://learn.microsoft.com/ko-kr/kusto/query/summarize-operator?view=microsoft-fabric |
| join ์ฐ์ฐ์ | join ์ข ๋ฅ์ ์ฌ์ฉ๋ฒ | https://learn.microsoft.com/ko-kr/kusto/query/join-operator?view=microsoft-fabric |
| mv-expand ์ฐ์ฐ์ | mv-expand ๊ณต์ ๋ฌธ์ | https://learn.microsoft.com/ko-kr/kusto/query/mv-expand-operator?view=microsoft-fabric |
| Azure Data Explorer | ADX(Azure Data Explorer) ๊ฐ์ | https://learn.microsoft.com/ko-kr/azure/data-explorer/data-explorer-overview |