<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>no 잼 no gain</title>
    <link>https://monkeybusiness.tistory.com/</link>
    <description>IT 지식 정리</description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 15:55:49 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>인생아</managingEditor>
    <image>
      <title>no 잼 no gain</title>
      <url>https://tistory1.daumcdn.net/tistory/2036009/attach/a5661193493741529711dc14ccfbe3d5</url>
      <link>https://monkeybusiness.tistory.com</link>
    </image>
    <item>
      <title>빅분기 실기 3유형 정리</title>
      <link>https://monkeybusiness.tistory.com/1099</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;벼락치기 문법 암기용으로 정리한 내용으로 틀린부분이 있을 수 있음&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;#1️⃣ chi2_contingency – 두 범주형 변수의 독립성 검정(카이제곱 검정)
# chi2_contingency : 두 범주형 변수의 독립성 검정(카이제곱 검정)

import pandas as pd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 데이터프레임 활용을 위해 pandas 불러오기
from scipy.stats import chi2_contingency&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 카이제곱 독립성 검정 함수 불러오기

# 예시용 데이터프레임 생성 (실제에선 이미 있는 df 사용)
df = pd.DataFrame({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'Resistin': ['low', 'low', 'high', 'high', 'low', 'high'],&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 범주형 변수 1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'Classification': ['normal', 'disease', 'normal', 'disease', 'normal', 'disease']&amp;nbsp;&amp;nbsp;# 범주형 변수 2
})

# 두 범주형 변수(Resistin, Classification)의 교차표(빈도표) 생성
table = pd.crosstab(df['Resistin'], df['Classification'])

# 카이제곱 독립성 검정 수행
chi2, p, dof, expected = chi2_contingency(table)

print(&quot;교차표\n&quot;, table)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 실제 관측된 교차표 출력
print(&quot;카이제곱 통계량:&quot;, chi2)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# chi-square 통계량 출력
print(&quot;p-value:&quot;, p)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 유의확률(p-value) 출력
print(&quot;자유도:&quot;, dof)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 자유도 출력
print(&quot;기대도수표\n&quot;, expected)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 기대도수표(귀무가설 하에서 기대되는 빈도) 출력

#2️⃣ chisquare – 한 범주형 변수의 분포 적합도 검정(카이제곱 적합도 검정)
# chisquare : 한 범주형 변수의 분포가 이론/기대 분포와 같은지 검정(카이제곱 적합도 검정)

import numpy as np&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 수치 배열 연산을 위해 numpy 불러오기
from scipy.stats import chisquare&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 카이제곱 적합도 검정 함수 불러오기

# 관측된 빈도 (예: 주사위 6면이 나온 횟수)
observed = np.array([8, 14, 10, 12, 9, 7])&amp;nbsp;&amp;nbsp; # 실제로 관측된 각 눈의 개수

# 기대되는 빈도 (예: 공정한 주사위라면 60번 중 각 눈이 10번씩 나와야 함)
expected = np.array([10, 10, 10, 10, 10, 10])&amp;nbsp;&amp;nbsp; # 이론적으로 기대되는 각 눈의 개수

# 카이제곱 적합도 검정 수행
chi2_stat, p = chisquare(f_obs=observed, f_exp=expected)

print(&quot;관측값:&quot;, observed)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 실제 관측 빈도 출력
print(&quot;기대값:&quot;, expected)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 이론/기대 빈도 출력
print(&quot;카이제곱 통계량:&quot;, chi2_stat)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# chi-square 통계량 출력
print(&quot;p-value:&quot;, p)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 유의확률(p-value) 출력

#3️⃣ ttest_1samp – 1표본 t-검정 (한 집단 평균 vs 기준값)
# ttest_1samp : 한 집단의 평균이 특정 기준값과 같은지/다른지 검정(1표본 t-검정)

import numpy as np&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 수치 데이터 생성을 위해 numpy 불러오기
from scipy.stats import ttest_1samp&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 1표본 t-검정 함수 불러오기

# 예시 데이터: 어떤 집단의 혈압 값들 (실제에선 df['혈압'] 같은 시리즈 사용 가능)
sample = np.array([118, 121, 119, 123, 117, 120, 122])&amp;nbsp;&amp;nbsp; # 한 집단의 연속형 데이터

mu0 = 120&amp;nbsp;&amp;nbsp; # 기준값(예: 정상 혈압 평균 120이라고 가정)

# 1표본 t-검정 수행 (귀무가설: 집단 평균 = mu0)
t_stat, p = ttest_1samp(sample, popmean=mu0)

print(&quot;샘플 데이터:&quot;, sample)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 사용한 샘플 데이터 출력
print(&quot;기준값(mu0):&quot;, mu0)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 비교 기준이 되는 평균값 출력
print(&quot;t-통계량:&quot;, t_stat)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # t 통계량 출력
print(&quot;p-value:&quot;, p)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 유의확률(p-value) 출력

#4️⃣ ttest_ind – 독립 2표본 t-검정 (서로 다른 두 집단 평균 비교)
# ttest_ind : 서로 다른 두 집단의 평균 차이를 검정(독립 2표본 t-검정)

import numpy as np&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 수치 데이터 생성을 위해 numpy 불러오기
from scipy.stats import ttest_ind&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 독립 2표본 t-검정 함수 불러오기

# 예시 데이터: 남자/여자의 키 데이터 (서로 독립된 두 집단)
group1 = np.array([175, 178, 180, 172, 177])&amp;nbsp;&amp;nbsp; # 집단1 예: 남자 키
group2 = np.array([162, 165, 168, 170, 166])&amp;nbsp;&amp;nbsp; # 집단2 예: 여자 키

# 독립 2표본 t-검정 수행 (기본: 등분산 가정 equal_var=True)
t_stat, p = ttest_ind(group1, group2, equal_var=True)

print(&quot;집단1 데이터:&quot;, group1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 첫 번째 집단 데이터 출력
print(&quot;집단2 데이터:&quot;, group2)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 두 번째 집단 데이터 출력
print(&quot;t-통계량:&quot;, t_stat)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # t 통계량 출력
print(&quot;p-value:&quot;, p)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 유의확률(p-value) 출력

#5️⃣ ttest_rel – 대응표본 t-검정 (같은 집단의 전/후 비교)
# ttest_rel : 같은 집단의 두 시점/두 조건 평균 차이를 검정(대응표본 t-검정)

import numpy as np&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 수치 데이터 생성을 위해 numpy 불러오기
from scipy.stats import ttest_rel&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 대응표본 t-검정 함수 불러오기

# 예시 데이터: 같은 사람들의 다이어트 전/후 몸무게
before = np.array([70, 68, 75, 80, 72])&amp;nbsp;&amp;nbsp; # 다이어트 전 몸무게
after&amp;nbsp;&amp;nbsp;= np.array([68, 67, 73, 78, 71])&amp;nbsp;&amp;nbsp; # 다이어트 후 몸무게

# 대응표본 t-검정 수행 (각 인덱스끼리 짝이 맞는 데이터)
t_stat, p = ttest_rel(before, after)

print(&quot;전(before):&quot;, before)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 전(처리 전) 데이터 출력
print(&quot;후(after):&quot;, after)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 후(처리 후) 데이터 출력
print(&quot;t-통계량:&quot;, t_stat)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # t 통계량 출력
print(&quot;p-value:&quot;, p)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 유의확률(p-value) 출력

#한 번에 요약해서 외우기
#chi2_contingency : 두 범주형 변수의 독립성 검정(카이제곱)
#chisquare : 한 범주형 변수의 분포 적합도 검정(카이제곱)
#ttest_1samp : 한 집단 평균 vs 기준값(1표본 t-검정)
#ttest_ind : 서로 다른 두 집단 평균 비교(독립 2표본 t-검정)
#ttest_rel : 같은 집단 전/후 평균 비교(대응표본 t-검정)








import pandas as pd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 데이터프레임 사용을 위해 pandas 불러오기
import numpy as np&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 수치 계산(지수, 로그 등)을 위해 numpy 불러오기
from statsmodels.api import Logit, OLS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 로지스틱 회귀(Logit), 선형회귀(OLS) 모델 클래스 불러오기

# 1-1. 회귀식(formula) 정의
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Servived ~ Gender + SibSp + Parch + Fare
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; → 종속변수: Servived (0/1)
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; → 독립변수: Gender, SibSp, Parch, Fare
formula_logit = &quot;Servived ~ Gender + SibSp + Parch + Fare&quot;

# 1-2. 로지스틱 회귀 모델 생성 (formula와 데이터프레임 df를 사용)
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Logit.from_formula(식, 데이터프레임)
logit_model = Logit.from_formula(formula_logit, df)

# 1-3. 모델 적합 (최대우도추정으로 계수 추정)
logit_results = logit_model.fit()

# 1-4. 결과 요약표 출력
print(&quot;\n=== [Logit] 결과 요약 ===&quot;)
print(logit_results.summary())&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 회귀 계수, 표준오차, z값, p-value, 설명력 등 출력

# ---------------------------------------------------
# 1-5. SibSp 계수의 odds ratio(승산비) 계산
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;※ 주의: results.param 이 아니라 results.params (복수형) 사용
# ---------------------------------------------------

# SibSp 계수 추출
coef_sibsp = logit_results.params['SibSp']
print(coef_sibsp)
# 계수를 지수변환하여 odds ratio(승산비) 계산
odds_ratio_sibsp = np.exp(coef_sibsp)

# 소수 3자리까지 반올림
odds_ratio_sibsp_round = round(odds_ratio_sibsp, 3)

print(&quot;\n=== [Logit] SibSp 계수 및 승산비 ===&quot;)
print(&quot;SibSp 계수:&quot;, coef_sibsp)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # 로짓 계수(로그 odds 단위)
print(&quot;SibSp odds ratio:&quot;, odds_ratio_sibsp_round)&amp;nbsp;&amp;nbsp; # 승산비(odds ratio)

# ==========================================================
# 2. OLS : 선형 회귀 (종속변수가 연속형일 때 사용)
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;종속변수: Fare (연속형)
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;독립변수: Gender, SibSp, Parch
# ==========================================================

# 2-1. 회귀식(formula) 정의
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Fare ~ Gender + SibSp + Parch
formula_ols = &quot;Fare ~ Gender + SibSp + Parch&quot;

# 2-2. OLS 선형 회귀 모델 생성 (formula와 df를 사용)
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;❗ 여기서 중요한 점:
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OLS(formula=..., data=...) 이렇게 쓰는 게 아니라
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OLS.from_formula(formula, data) 를 써야 함
ols_model = OLS.from_formula(formula_ols, df)

# 2-3. 모델 적합 (최소제곱법으로 계수 추정)
ols_results = ols_model.fit()

# 2-4. 결과 요약표 출력
print(&quot;\n=== [OLS] 결과 요약 ===&quot;)
print(ols_results.summary())&amp;nbsp;&amp;nbsp; # 회귀 계수, 표준오차, t값, p-value, R-squared(설명력) 등 출력













# OLS : 선형 회귀 (종속변수가 연속형일 때 사용)

import pandas as pd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 데이터프레임 사용
from statsmodels.api import OLS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# formula 기반 선형회귀(ols) 사용을 위해 불러오기

# 예시 데이터프레임 df가 있다고 가정
# df에는 Fare(연속형), Gender, SibSp, Parch 같은 컬럼이 있다고 가정

# 1. 회귀식(formula) 정의
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Fare ~ Gender + SibSp + Parch
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;→ 종속변수: Fare (연속형)
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;→ 독립변수: Gender, SibSp, Parch
formula_ols = &quot;Fare ~ Gender + SibSp + Parch&quot;

# 2. OLS 선형 회귀 모델 생성 (formula와 df를 사용)
ols_model = OLS(formula=formula_ols, data=df)

# 3. 모델 적합 (최소제곱법으로 계수 추정)
ols_results = ols_model.fit()

# 4. 결과 요약표 출력
print(ols_results.summary())&amp;nbsp;&amp;nbsp; # 회귀 계수, 표준오차, t값, p-value, R-squared(설명력) 등 출력









# 1번 F-검정 검정통계량
df['log_resistin'] = np.log(df['Resistin'])

group1 = df[df['Classification'] == 1]['log_resistin']
group2 = df[df['Classification'] == 2]['log_resistin']
var1 = group1.var()
var2 = group2.var()

dof_1 = len(group1)-1
dof_2 = len(group2)-2

f_stat = var2/var1
print(round(f_stat,3))

# 2번 합동분산추정량
n1 = len(group1)
n2 = len(group2)

pooled_var = ((n1-1)*var1 + (n2-1)*var2) / (n1+n2-2)
print(round(pooled_var),3)

from scipy.stats import ttest_ind
ttest_ind_result = ttest_ind(group1, group2)
print(ttest_ind_result)&lt;/code&gt;&lt;/pre&gt;</description>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1099</guid>
      <comments>https://monkeybusiness.tistory.com/1099#entry1099comment</comments>
      <pubDate>Sat, 29 Nov 2025 00:27:53 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] JSON_VALID, JSON_UNQUOTE 등 유틸 함수 총정리</title>
      <link>https://monkeybusiness.tistory.com/1098</link>
      <description>&lt;p data-end=&quot;382&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 JSON 데이터를 다루기 위한 &lt;b&gt;검사/문자열/보조 기능&lt;/b&gt;을 제공하는 유틸리티 함수들을 갖추고 있다. 이 함수들은 복잡한 JSON 연산보다는 &lt;b&gt;가볍게 확인하거나 보정할 때 매우 유용&lt;/b&gt;하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lq3LU/btsPCiiEsJn/vazt8d713rVXkxenW9WcM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lq3LU/btsPCiiEsJn/vazt8d713rVXkxenW9WcM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lq3LU/btsPCiiEsJn/vazt8d713rVXkxenW9WcM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLq3LU%2FbtsPCiiEsJn%2Fvazt8d713rVXkxenW9WcM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;549&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;413&quot; data-start=&quot;384&quot; data-ke-size=&quot;size26&quot;&gt;1. JSON_VALID: JSON 유효성 확인&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677902696&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_VALID(json_val)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;497&quot; data-start=&quot;448&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;476&quot; data-start=&quot;448&quot;&gt;JSON 문자열이 &lt;b&gt;정상적인 형식인지 검사&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;497&quot; data-start=&quot;477&quot;&gt;1이면 유효, 0이면 무효&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;505&quot; data-start=&quot;499&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677908159&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_VALID('{&quot;name&quot;: &quot;철수&quot;}');
-- 결과: 1

SELECT JSON_VALID('&quot;name&quot;: &quot;철수&quot;');
-- 결과: 0 (잘못된 형식)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;660&quot; data-start=&quot;619&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;660&quot; data-start=&quot;619&quot;&gt;&lt;b&gt;INSERT 전에 JSON 형식이 맞는지 체크&lt;/b&gt;할 때 자주 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;697&quot; data-start=&quot;662&quot; data-ke-size=&quot;size26&quot;&gt;2. JSON_UNQUOTE: JSON 문자열 따옴표 제거&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677915328&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_UNQUOTE(json_val)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;762&quot; data-start=&quot;734&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;762&quot; data-start=&quot;734&quot;&gt;JSON 문자열의 &lt;b&gt;양쪽 따옴표(&quot;)&lt;/b&gt; 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;770&quot; data-start=&quot;764&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677920735&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_UNQUOTE('&quot;철수&quot;');
-- 결과: 철수

SELECT JSON_UNQUOTE('25');
-- 결과: 25 (숫자는 그대로)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;932&quot; data-start=&quot;871&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;932&quot; data-start=&quot;871&quot;&gt;JSON_EXTRACT() 결과값이 &quot;홍길동&quot;처럼 따옴표 포함일 때,&lt;br /&gt;문자열 처리 용도로 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677928792&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_UNQUOTE(JSON_EXTRACT('{&quot;name&quot;: &quot;홍길동&quot;}', '$.name'));
-- 결과: 홍길동&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1047&quot; data-start=&quot;1021&quot; data-ke-size=&quot;size26&quot;&gt;3. JSON_TYPE: 데이터 타입 확인&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677935335&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_TYPE(json_doc[, path])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1146&quot; data-start=&quot;1089&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1146&quot; data-start=&quot;1089&quot;&gt;대상 값의 타입을 반환 (OBJECT, ARRAY, STRING, INTEGER 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1154&quot; data-start=&quot;1148&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677940895&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_TYPE('{&quot;name&quot;: &quot;철수&quot;}', '$.name');
-- 결과: STRING

SELECT JSON_TYPE('[&quot;A&quot;, &quot;B&quot;]');
-- 결과: ARRAY&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1300&quot; data-start=&quot;1274&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1300&quot; data-start=&quot;1274&quot;&gt;&lt;b&gt;CASE WHEN 조건문에 활용&lt;/b&gt; 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1332&quot; data-start=&quot;1302&quot; data-ke-size=&quot;size26&quot;&gt;4. JSON_DEPTH: JSON의 깊이 구하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677948111&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_DEPTH(json_doc)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1391&quot; data-start=&quot;1367&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1391&quot; data-start=&quot;1367&quot;&gt;중첩된 JSON 구조의 최대 깊이를 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1399&quot; data-start=&quot;1393&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677953984&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_DEPTH('{&quot;a&quot;: 1}');
-- 결과: 1

SELECT JSON_DEPTH('{&quot;a&quot;: {&quot;b&quot;: {&quot;c&quot;: 3}}}');
-- 결과: 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1520&quot; data-start=&quot;1508&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1520&quot; data-start=&quot;1508&quot;&gt;구조 분석 시 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1558&quot; data-start=&quot;1522&quot; data-ke-size=&quot;size26&quot;&gt;5. JSON_QUOTE: 문자열을 JSON 문자열로 감싸기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677959944&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_QUOTE(string_val)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1634&quot; data-start=&quot;1595&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1634&quot; data-start=&quot;1595&quot;&gt;문자열을 JSON 문자열로 변환 (따옴표 추가 + 이스케이프 처리)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1642&quot; data-start=&quot;1636&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677964775&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_QUOTE('철수');
-- 결과: &quot;철수&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1716&quot; data-start=&quot;1693&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1716&quot; data-start=&quot;1693&quot;&gt;반대 함수가 JSON_UNQUOTE&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1754&quot; data-start=&quot;1718&quot; data-ke-size=&quot;size26&quot;&gt;6. JSON_STORAGE_SIZE: 저장 공간 크기 확인&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677969199&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_STORAGE_SIZE(json_doc)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1827&quot; data-start=&quot;1796&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1827&quot; data-start=&quot;1796&quot;&gt;내부적으로 JSON이 차지하는 &lt;b&gt;바이트 수&lt;/b&gt; 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1835&quot; data-start=&quot;1829&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677977783&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_STORAGE_SIZE('{&quot;name&quot;: &quot;홍길동&quot;}');
-- 결과: 20 (예시값)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1932&quot; data-start=&quot;1910&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1932&quot; data-start=&quot;1910&quot;&gt;용량 제한 관리나 DB 튜닝 시 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1951&quot; data-start=&quot;1934&quot; data-ke-size=&quot;size26&quot;&gt;7. 실무 팁: 조합 활용&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677982785&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  JSON_UNQUOTE(profile -&amp;gt; '$.name') AS 이름,
  JSON_TYPE(profile, '$.age') AS 나이타입,
  JSON_VALID(profile) AS 유효여부
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2160&quot; data-start=&quot;2097&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2160&quot; data-start=&quot;2097&quot;&gt;JSON 데이터를 &lt;b&gt;문자열처럼 출력하고&lt;/b&gt;, &lt;b&gt;타입 확인하고&lt;/b&gt;, &lt;b&gt;정상 여부 검사&lt;/b&gt;까지 한 번에 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2170&quot; data-start=&quot;2162&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2239&quot; data-start=&quot;2172&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2349&quot; data-start=&quot;2257&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>json</category>
      <category>JSON_UNQUOTE</category>
      <category>JSON_VALID</category>
      <category>JSON기초함수</category>
      <category>JSON유틸함수</category>
      <category>JSON형식검사</category>
      <category>MYSQL</category>
      <category>MySQL문자열처리</category>
      <category>mysql실무예제</category>
      <category>SQLJSON검사</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1098</guid>
      <comments>https://monkeybusiness.tistory.com/1098#entry1098comment</comments>
      <pubDate>Mon, 28 Jul 2025 19:47:03 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] JSON_MERGE, JSON_ARRAY_APPEND 활용법</title>
      <link>https://monkeybusiness.tistory.com/1097</link>
      <description>&lt;p data-end=&quot;399&quot; data-start=&quot;228&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 JSON 객체를 합치거나 배열에 값을 추가하는 다양한 함수가 제공된다. 그중 대표적인 것이 &lt;b&gt;JSON_MERGE_PRESERVE()&lt;/b&gt;, &lt;b&gt;JSON_ARRAY_APPEND()&lt;/b&gt; 함수다. 특히 REST API 응답 구조, 사용자 이력 기록, 동적 필드 추가 등에서 매우 유용하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQWtRE/btsPBoRnHVV/3hMdJMW5SXfoOENvzRt011/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQWtRE/btsPBoRnHVV/3hMdJMW5SXfoOENvzRt011/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQWtRE/btsPBoRnHVV/3hMdJMW5SXfoOENvzRt011/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQWtRE%2FbtsPBoRnHVV%2F3hMdJMW5SXfoOENvzRt011%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;520&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;437&quot; data-start=&quot;401&quot; data-ke-size=&quot;size26&quot;&gt;1. JSON_MERGE_PRESERVE: JSON 병합하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677002913&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_MERGE_PRESERVE(json_doc1, json_doc2, ...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;546&quot; data-start=&quot;498&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;521&quot; data-start=&quot;498&quot;&gt;여러 JSON 객체/배열을 하나로 병합&lt;/li&gt;
&lt;li data-end=&quot;546&quot; data-start=&quot;522&quot;&gt;&lt;b&gt;동일 키가 중복되면 배열로 합쳐짐&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;561&quot; data-start=&quot;548&quot; data-ke-size=&quot;size23&quot;&gt;예제: 객체 병합&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677008426&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_MERGE_PRESERVE(
  '{&quot;name&quot;: &quot;철수&quot;}',
  '{&quot;age&quot;: 30}'
);
-- 결과: {&quot;name&quot;: &quot;철수&quot;, &quot;age&quot;: 30}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;690&quot; data-start=&quot;675&quot; data-ke-size=&quot;size23&quot;&gt;예제: 중복 키 병합&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677016151&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_MERGE_PRESERVE(
  '{&quot;name&quot;: &quot;철수&quot;}',
  '{&quot;name&quot;: &quot;영희&quot;}'
);
-- 결과: {&quot;name&quot;: [&quot;철수&quot;, &quot;영희&quot;]}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;842&quot; data-start=&quot;804&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;842&quot; data-start=&quot;804&quot;&gt;key 중복 시 값을 &lt;b&gt;배열로 묶어 병합&lt;/b&gt;한다는 특징이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;857&quot; data-start=&quot;844&quot; data-ke-size=&quot;size23&quot;&gt;예제: 배열 병합&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677021696&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_MERGE_PRESERVE(
  '[&quot;A&quot;, &quot;B&quot;]',
  '[&quot;C&quot;, &quot;D&quot;]'
);
-- 결과: [&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;D&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;998&quot; data-start=&quot;961&quot; data-ke-size=&quot;size26&quot;&gt;2. JSON_MERGE_PATCH (MySQL 8.0.3+)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677029431&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_MERGE_PATCH(json_doc1, json_doc2)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1094&quot; data-start=&quot;1051&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1068&quot; data-start=&quot;1051&quot;&gt;&lt;b&gt;중복 key는 덮어씀&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1094&quot; data-start=&quot;1069&quot;&gt;JSON 객체만 대상 (배열은 사용 불가)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677034871&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_MERGE_PATCH(
  '{&quot;name&quot;: &quot;철수&quot;}',
  '{&quot;name&quot;: &quot;영희&quot;}'
);
-- 결과: {&quot;name&quot;: &quot;영희&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1245&quot; data-start=&quot;1197&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1245&quot; data-start=&quot;1197&quot;&gt;JSON_MERGE_PATCH는 RESTful API의 PATCH 작업처럼 작동&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1280&quot; data-start=&quot;1247&quot; data-ke-size=&quot;size26&quot;&gt;3. JSON_ARRAY_APPEND: 배열에 값 추가&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677041016&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_ARRAY_APPEND(json_doc, path, value[, path, value] ...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1378&quot; data-start=&quot;1354&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1378&quot; data-start=&quot;1354&quot;&gt;지정된 경로(일반적으로 배열)에 값 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1386&quot; data-start=&quot;1380&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677046226&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_ARRAY_APPEND('[&quot;A&quot;, &quot;B&quot;]', '$', &quot;C&quot;);
-- 결과: [&quot;A&quot;, &quot;B&quot;, &quot;C&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1490&quot; data-start=&quot;1473&quot; data-ke-size=&quot;size23&quot;&gt;객체 내 배열에 값 추가&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677052600&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_ARRAY_APPEND(
  '{&quot;tags&quot;: [&quot;sql&quot;, &quot;json&quot;]}',
  '$.tags',
  'mysql'
);
-- 결과: {&quot;tags&quot;: [&quot;sql&quot;, &quot;json&quot;, &quot;mysql&quot;]}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1643&quot; data-start=&quot;1628&quot; data-ke-size=&quot;size23&quot;&gt;여러 위치 동시 추가&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677061159&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_ARRAY_APPEND(
  '{&quot;a&quot;: [1], &quot;b&quot;: [10]}',
  '$.a', 2,
  '$.b', 20
);
-- 결과: {&quot;a&quot;: [1, 2], &quot;b&quot;: [10, 20]}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1787&quot; data-start=&quot;1773&quot; data-ke-size=&quot;size26&quot;&gt;4. 실무 활용 예제&lt;/h2&gt;
&lt;h3 data-end=&quot;1805&quot; data-start=&quot;1789&quot; data-ke-size=&quot;size23&quot;&gt;사용자 로그 누적 저장&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677066911&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE users
SET history = JSON_ARRAY_APPEND(history, '$', '로그인')
WHERE id = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1935&quot; data-start=&quot;1899&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1935&quot; data-start=&quot;1899&quot;&gt;history가 배열로 되어 있을 때, 새로운 활동 추가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1956&quot; data-start=&quot;1937&quot; data-ke-size=&quot;size23&quot;&gt;여러 필드에 동시에 값 추가&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753677073863&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE products
SET meta = JSON_ARRAY_APPEND(meta, '$.tags', '신상품', '$.colors', 'blue')
WHERE id = 101;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2107&quot; data-start=&quot;2074&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2107&quot; data-start=&quot;2074&quot;&gt;tags와 colors 모두 배열로 존재해야 동작&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2150&quot; data-start=&quot;2109&quot; data-ke-size=&quot;size26&quot;&gt;5. JSON_MERGE와 JSON_ARRAY_APPEND 차이 정리&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2553&quot; data-start=&quot;2152&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;JSON_MERGE_PRESERVE&lt;/td&gt;
&lt;td&gt;JSON_ARRAY_APPEND&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2363&quot; data-start=&quot;2302&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2323&quot; data-start=&quot;2302&quot;&gt;목적&lt;/td&gt;
&lt;td data-end=&quot;2343&quot; data-start=&quot;2323&quot; data-col-size=&quot;sm&quot;&gt;객체/배열 병합&lt;/td&gt;
&lt;td data-end=&quot;2363&quot; data-start=&quot;2343&quot; data-col-size=&quot;sm&quot;&gt;배열에 값 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2428&quot; data-start=&quot;2364&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2383&quot; data-start=&quot;2364&quot;&gt;대상 경로&lt;/td&gt;
&lt;td data-end=&quot;2407&quot; data-start=&quot;2383&quot; data-col-size=&quot;sm&quot;&gt;전체 JSON&lt;/td&gt;
&lt;td data-end=&quot;2428&quot; data-start=&quot;2407&quot; data-col-size=&quot;sm&quot;&gt;경로(path) 명시 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2493&quot; data-start=&quot;2429&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2447&quot; data-start=&quot;2429&quot;&gt;중복 키 처리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2469&quot; data-start=&quot;2447&quot;&gt;배열로 병합&lt;/td&gt;
&lt;td data-end=&quot;2493&quot; data-start=&quot;2469&quot; data-col-size=&quot;sm&quot;&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2553&quot; data-start=&quot;2494&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2512&quot; data-start=&quot;2494&quot;&gt;실무 용도 예&lt;/td&gt;
&lt;td data-end=&quot;2535&quot; data-start=&quot;2512&quot; data-col-size=&quot;sm&quot;&gt;다수 JSON 통합&lt;/td&gt;
&lt;td data-end=&quot;2553&quot; data-start=&quot;2535&quot; data-col-size=&quot;sm&quot;&gt;히스토리 누적, 태그 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2563&quot; data-start=&quot;2555&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2705&quot; data-start=&quot;2565&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-merge-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-merge-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2818&quot; data-start=&quot;2723&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>json</category>
      <category>JSONMERGE</category>
      <category>JSON_ARRAY_APPEND</category>
      <category>JSON배열추가</category>
      <category>JSON병합</category>
      <category>JSON확장함수</category>
      <category>MYSQL</category>
      <category>MySQLJSON활용</category>
      <category>mysql실무예제</category>
      <category>SQLJSON처리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1097</guid>
      <comments>https://monkeybusiness.tistory.com/1097#entry1097comment</comments>
      <pubDate>Mon, 28 Jul 2025 18:52:17 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] JSON_CONTAINS, JSON_LENGTH 등 검사 함수 모음</title>
      <link>https://monkeybusiness.tistory.com/1096</link>
      <description>&lt;p data-end=&quot;422&quot; data-start=&quot;245&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 JSON 데이터를 다루다 보면 내부에 특정 값이 &lt;b&gt;존재하는지 확인하거나&lt;/b&gt;, &lt;b&gt;배열/객체의 크기를 계산&lt;/b&gt;하는 일이 자주 발생한다. 이럴 때 사용하는 것이 &lt;b&gt;JSON_CONTAINS, JSON_LENGTH, JSON_CONTAINS_PATH, JSON_TYPE&lt;/b&gt; 등의 &lt;b&gt;검사 함수&lt;/b&gt;다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VJoSn/btsPBjbnClv/b01pL5sjfL09acSiIBjzkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VJoSn/btsPBjbnClv/b01pL5sjfL09acSiIBjzkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VJoSn/btsPBjbnClv/b01pL5sjfL09acSiIBjzkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVJoSn%2FbtsPBjbnClv%2Fb01pL5sjfL09acSiIBjzkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;549&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;455&quot; data-start=&quot;424&quot; data-ke-size=&quot;size26&quot;&gt;1. JSON_CONTAINS: 값 포함 여부 확인&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675122087&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_CONTAINS(target_json, candidate_json[, path])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;595&quot; data-start=&quot;520&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;569&quot; data-start=&quot;520&quot;&gt;target_json에 candidate_json이 포함되어 있는지 여부 반환&lt;/li&gt;
&lt;li data-end=&quot;595&quot; data-start=&quot;570&quot;&gt;반환값: 1 (존재), 0 (없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;603&quot; data-start=&quot;597&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675127927&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_CONTAINS('[&quot;A&quot;, &quot;B&quot;, &quot;C&quot;]', '&quot;B&quot;');
-- 결과: 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675135623&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_CONTAINS('{&quot;name&quot;: &quot;철수&quot;, &quot;age&quot;: 25}', '{&quot;age&quot;: 25}');
-- 결과: 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;773&quot; data-start=&quot;761&quot; data-ke-size=&quot;size23&quot;&gt;경로 지정 예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675143567&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_CONTAINS('{&quot;user&quot;: {&quot;name&quot;: &quot;영희&quot;}}', '&quot;영희&quot;', '$.user.name');
-- 결과: 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;899&quot; data-start=&quot;869&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;899&quot; data-start=&quot;869&quot;&gt;JSON 경로를 명시하면 중첩 구조에서도 탐색 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;938&quot; data-start=&quot;901&quot; data-ke-size=&quot;size26&quot;&gt;2. JSON_CONTAINS_PATH: 경로 존재 여부 확인&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675150008&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_CONTAINS_PATH(json_doc, 'one'|'all', path1[, path2, ...])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1058&quot; data-start=&quot;1015&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1037&quot; data-start=&quot;1015&quot;&gt;'one': 하나라도 존재하면 1&lt;/li&gt;
&lt;li data-end=&quot;1058&quot; data-start=&quot;1038&quot;&gt;'all': 모두 존재해야 1&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1066&quot; data-start=&quot;1060&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675155359&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_CONTAINS_PATH('{&quot;a&quot;:1, &quot;b&quot;:2}', 'one', '$.a', '$.x');
-- 결과: 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675161535&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_CONTAINS_PATH('{&quot;a&quot;:1, &quot;b&quot;:2}', 'all', '$.a', '$.x');
-- 결과: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1270&quot; data-start=&quot;1242&quot; data-ke-size=&quot;size26&quot;&gt;3. JSON_LENGTH: 요소 개수 구하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675166695&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_LENGTH(json_doc[, path])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1348&quot; data-start=&quot;1314&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1331&quot; data-start=&quot;1314&quot;&gt;JSON 객체: key 개수&lt;/li&gt;
&lt;li data-end=&quot;1348&quot; data-start=&quot;1332&quot;&gt;JSON 배열: 요소 개수&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1356&quot; data-start=&quot;1350&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675173583&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_LENGTH('{&quot;a&quot;:1, &quot;b&quot;:2}');
-- 결과: 2

SELECT JSON_LENGTH('[&quot;x&quot;, &quot;y&quot;, &quot;z&quot;]');
-- 결과: 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1478&quot; data-start=&quot;1466&quot; data-ke-size=&quot;size23&quot;&gt;경로 지정 예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675180415&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_LENGTH('{&quot;data&quot;: [1, 2, 3]}', '$.data');
-- 결과: 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1579&quot; data-start=&quot;1554&quot; data-ke-size=&quot;size26&quot;&gt;4. JSON_TYPE: 값의 타입 확인&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675189200&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_TYPE(json_doc[, path])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1675&quot; data-start=&quot;1621&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1675&quot; data-start=&quot;1621&quot;&gt;결과: OBJECT, ARRAY, INTEGER, STRING, NULL 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1683&quot; data-start=&quot;1677&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675194511&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_TYPE('{&quot;x&quot;: 1}', '$.x');
-- 결과: INTEGER&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675199039&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_TYPE('[10, 20, 30]');
-- 결과: ARRAY&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1840&quot; data-start=&quot;1808&quot; data-ke-size=&quot;size26&quot;&gt;5. JSON_VALID: 유효한 JSON 여부 검사&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675205281&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_VALID('{&quot;a&quot;: 1}');       -- 결과: 1
SELECT JSON_VALID('&quot;a&quot;: 1');         -- 결과: 0 (유효하지 않음)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2009&quot; data-start=&quot;1956&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1978&quot; data-start=&quot;1956&quot;&gt;JSON 데이터 유효성 검증 시 사용&lt;/li&gt;
&lt;li data-end=&quot;2009&quot; data-start=&quot;1979&quot;&gt;INSERT 또는 UPDATE 전에 확인할 때 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2024&quot; data-start=&quot;2011&quot; data-ke-size=&quot;size26&quot;&gt;6. 실무 활용 팁&lt;/h2&gt;
&lt;h3 data-end=&quot;2050&quot; data-start=&quot;2026&quot; data-ke-size=&quot;size23&quot;&gt;특정 필드가 존재할 때만 SELECT&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675212671&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM users
WHERE JSON_CONTAINS_PATH(profile, 'one', '$.nickname');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2169&quot; data-start=&quot;2140&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2169&quot; data-start=&quot;2140&quot;&gt;nickname 필드가 존재하는 사용자만 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2196&quot; data-start=&quot;2171&quot; data-ke-size=&quot;size23&quot;&gt;배열 크기가 일정 이상인 데이터 필터링&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675217569&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM logs
WHERE JSON_LENGTH(tags) &amp;gt;= 3;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2291&quot; data-start=&quot;2259&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2291&quot; data-start=&quot;2259&quot;&gt;tags 배열에 3개 이상 태그가 있는 로그만 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2308&quot; data-start=&quot;2293&quot; data-ke-size=&quot;size23&quot;&gt;유효성 확인 후 삽입&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675224095&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO products (id, spec)
SELECT 1, '{&quot;cpu&quot;: &quot;i5&quot;}'
WHERE JSON_VALID('{&quot;cpu&quot;: &quot;i5&quot;}') = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2445&quot; data-start=&quot;2419&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2445&quot; data-start=&quot;2419&quot;&gt;JSON 형식이 맞을 때만 INSERT 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2455&quot; data-start=&quot;2447&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2593&quot; data-start=&quot;2457&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2704&quot; data-start=&quot;2611&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>json</category>
      <category>jsoncontains</category>
      <category>JSONLENGTH</category>
      <category>JSON데이터검사</category>
      <category>JSON유효성</category>
      <category>JSON조건검색</category>
      <category>MYSQL</category>
      <category>MySQLJSON함수</category>
      <category>mysql실무예제</category>
      <category>SQLJSON분석</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1096</guid>
      <comments>https://monkeybusiness.tistory.com/1096#entry1096comment</comments>
      <pubDate>Mon, 28 Jul 2025 17:50:08 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] JSON_SET, JSON_REPLACE로 값 수정하기</title>
      <link>https://monkeybusiness.tistory.com/1095</link>
      <description>&lt;p data-end=&quot;402&quot; data-start=&quot;245&quot; data-ke-size=&quot;size16&quot;&gt;MySQL의 JSON_SET()과 JSON_REPLACE() 함수는 JSON 컬럼 내의 특정 경로 값을 &lt;b&gt;수정하거나 조건부로 대체&lt;/b&gt;할 때 사용된다. 두 함수 모두 원본 JSON을 수정한 &lt;b&gt;새로운 JSON 값을 반환&lt;/b&gt;하므로, UPDATE 구문과 함께 자주 사용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9YaZ0/btsPAN48LYQ/7eKKHAKj8ia0y8hWDkHXpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9YaZ0/btsPAN48LYQ/7eKKHAKj8ia0y8hWDkHXpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9YaZ0/btsPAN48LYQ/7eKKHAKj8ia0y8hWDkHXpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9YaZ0%2FbtsPAN48LYQ%2F7eKKHAKj8ia0y8hWDkHXpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;573&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;423&quot; data-start=&quot;404&quot; data-ke-size=&quot;size26&quot;&gt;1. JSON_SET 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674923111&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_SET(json_doc, path, value[, path, value] ...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;557&quot; data-start=&quot;488&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;513&quot; data-start=&quot;488&quot;&gt;지정한 path에 value를 할당&lt;/li&gt;
&lt;li data-end=&quot;557&quot; data-start=&quot;514&quot;&gt;해당 키가 존재하면 &lt;b&gt;덮어쓰기&lt;/b&gt;, 존재하지 않으면 &lt;b&gt;새 키로 추가&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;565&quot; data-start=&quot;559&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674928056&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_SET('{&quot;name&quot;: &quot;홍길동&quot;}', '$.age', 30);
-- 결과: {&quot;name&quot;: &quot;홍길동&quot;, &quot;age&quot;: 30}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;682&quot; data-start=&quot;662&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;682&quot; data-start=&quot;662&quot;&gt;기존에 age가 없으면 추가됨&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674934023&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_SET('{&quot;name&quot;: &quot;홍길동&quot;, &quot;age&quot;: 25}', '$.age', 30);
-- 결과: {&quot;name&quot;: &quot;홍길동&quot;, &quot;age&quot;: 30}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;811&quot; data-start=&quot;790&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;811&quot; data-start=&quot;790&quot;&gt;기존 키가 있으면 해당 값 덮어쓰기&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;836&quot; data-start=&quot;813&quot; data-ke-size=&quot;size26&quot;&gt;2. JSON_REPLACE 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674938856&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_REPLACE(json_doc, path, value[, path, value] ...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;970&quot; data-start=&quot;905&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;941&quot; data-start=&quot;905&quot;&gt;지정한 path에 키가 존재할 경우에만 &lt;b&gt;값을 덮어씀&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;970&quot; data-start=&quot;942&quot;&gt;해당 경로가 없으면 &lt;b&gt;변경 없이 원본 유지&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;978&quot; data-start=&quot;972&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674946376&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_REPLACE('{&quot;name&quot;: &quot;영희&quot;}', '$.age', 30);
-- 결과: {&quot;name&quot;: &quot;영희&quot;}  &amp;larr; 아무 변화 없음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674955248&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_REPLACE('{&quot;name&quot;: &quot;영희&quot;, &quot;age&quot;: 25}', '$.age', 30);
-- 결과: {&quot;name&quot;: &quot;영희&quot;, &quot;age&quot;: 30}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1222&quot; data-start=&quot;1186&quot; data-ke-size=&quot;size26&quot;&gt;3. JSON_SET vs JSON_REPLACE 비교 정리&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1553&quot; data-start=&quot;1224&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;JSON_SET&lt;/td&gt;
&lt;td&gt;JSON_REPLACE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1434&quot; data-start=&quot;1372&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1386&quot; data-start=&quot;1372&quot;&gt;키 존재 시&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1409&quot; data-start=&quot;1386&quot;&gt;값 덮어씀&lt;/td&gt;
&lt;td data-end=&quot;1434&quot; data-start=&quot;1409&quot; data-col-size=&quot;sm&quot;&gt;값 덮어씀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1492&quot; data-start=&quot;1435&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1448&quot; data-start=&quot;1435&quot;&gt;키 미존재 시&lt;/td&gt;
&lt;td data-end=&quot;1471&quot; data-start=&quot;1448&quot; data-col-size=&quot;sm&quot;&gt;새로 추가&lt;/td&gt;
&lt;td data-end=&quot;1492&quot; data-start=&quot;1471&quot; data-col-size=&quot;sm&quot;&gt;아무 일도 하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1553&quot; data-start=&quot;1493&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1508&quot; data-start=&quot;1493&quot;&gt;주 용도&lt;/td&gt;
&lt;td data-end=&quot;1530&quot; data-start=&quot;1508&quot; data-col-size=&quot;sm&quot;&gt;값 수정 + 추가&lt;/td&gt;
&lt;td data-end=&quot;1553&quot; data-start=&quot;1530&quot; data-col-size=&quot;sm&quot;&gt;조건부 값 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1575&quot; data-start=&quot;1555&quot; data-ke-size=&quot;size26&quot;&gt;4. 테이블 컬럼 값 수정 예제&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674974946&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE users (
  id INT,
  profile JSON
);

INSERT INTO users VALUES
(1, '{&quot;name&quot;: &quot;철수&quot;, &quot;age&quot;: 20}'),
(2, '{&quot;name&quot;: &quot;영희&quot;}');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1741&quot; data-start=&quot;1721&quot; data-ke-size=&quot;size23&quot;&gt;JSON_SET으로 추가/수정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674980167&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE users
SET profile = JSON_SET(profile, '$.age', 30)
WHERE id = 2;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1859&quot; data-start=&quot;1827&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1859&quot; data-start=&quot;1827&quot;&gt;age가 없는 경우 &amp;rarr; &quot;age&quot;: 30 추가됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1884&quot; data-start=&quot;1861&quot; data-ke-size=&quot;size23&quot;&gt;JSON_REPLACE로 조건 수정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674986408&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE users
SET profile = JSON_REPLACE(profile, '$.age', 40)
WHERE id = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1995&quot; data-start=&quot;1974&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1995&quot; data-start=&quot;1974&quot;&gt;age 키가 존재할 때만 수정됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2014&quot; data-start=&quot;1997&quot; data-ke-size=&quot;size26&quot;&gt;5. 중첩 객체 경로 수정&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674993791&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_SET(
  '{&quot;user&quot;: {&quot;name&quot;: &quot;민수&quot;, &quot;email&quot;: &quot;a@b.com&quot;}}',
  '$.user.email', 'new@domain.com'
);
-- 결과: {&quot;user&quot;: {&quot;name&quot;: &quot;민수&quot;, &quot;email&quot;: &quot;new@domain.com&quot;}}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2229&quot; data-start=&quot;2192&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2229&quot; data-start=&quot;2192&quot;&gt;중첩 경로도 정확히 지정 가능 ('$.user.email')&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2250&quot; data-start=&quot;2231&quot; data-ke-size=&quot;size26&quot;&gt;6. 배열 요소 수정 (주의)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674999489&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_SET('[&quot;A&quot;, &quot;B&quot;, &quot;C&quot;]', '$[1]', &quot;X&quot;);
-- 결과: [&quot;A&quot;, &quot;X&quot;, &quot;C&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2355&quot; data-start=&quot;2336&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2355&quot; data-start=&quot;2336&quot;&gt;배열의 특정 인덱스도 수정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675004703&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_REPLACE('[&quot;A&quot;, &quot;B&quot;, &quot;C&quot;]', '$[5]', &quot;Z&quot;);
-- 결과: [&quot;A&quot;, &quot;B&quot;, &quot;C&quot;] (인덱스가 없으므로 변화 없음)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2495&quot; data-start=&quot;2463&quot; data-ke-size=&quot;size26&quot;&gt;7. 실무 팁: UPDATE + JSON_SET 조합&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675010815&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE users
SET profile = JSON_SET(profile, '$.updated_at', NOW())
WHERE id = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2636&quot; data-start=&quot;2591&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2609&quot; data-start=&quot;2591&quot;&gt;JSON 안에 타임스탬프 기록&lt;/li&gt;
&lt;li data-end=&quot;2636&quot; data-start=&quot;2610&quot;&gt;&lt;b&gt;변경이력 관리&lt;/b&gt; 등 실무에 자주 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2656&quot; data-start=&quot;2638&quot; data-ke-size=&quot;size26&quot;&gt;8. 한 번에 여러 키 수정&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753675017295&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_SET(
  '{&quot;a&quot;: 1, &quot;b&quot;: 2}',
  '$.a', 10,
  '$.b', 20,
  '$.c', 30
);
-- 결과: {&quot;a&quot;: 10, &quot;b&quot;: 20, &quot;c&quot;: 30}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2816&quot; data-start=&quot;2785&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2816&quot; data-start=&quot;2785&quot;&gt;한 번의 함수 호출로 여러 필드 동시 수정/추가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2826&quot; data-start=&quot;2818&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2900&quot; data-start=&quot;2828&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3006&quot; data-start=&quot;2918&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>json</category>
      <category>jsonreplace</category>
      <category>jsonset</category>
      <category>JSON값수정</category>
      <category>JSON변경함수</category>
      <category>JSON업데이트</category>
      <category>MYSQL</category>
      <category>MySQLJSON갱신</category>
      <category>MySQL함수활용</category>
      <category>SQLJSON처리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1095</guid>
      <comments>https://monkeybusiness.tistory.com/1095#entry1095comment</comments>
      <pubDate>Mon, 28 Jul 2025 16:57:42 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] JSON_EXTRACT와 -&amp;gt; 연산자로 값 조회하기</title>
      <link>https://monkeybusiness.tistory.com/1094</link>
      <description>&lt;p data-end=&quot;371&quot; data-start=&quot;218&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 JSON 타입 컬럼에 저장된 데이터는 &lt;b&gt;단순 문자열이 아닌 구조화된 객체&lt;/b&gt;이므로, 내부 값을 효율적으로 추출할 수 있는 전용 함수와 연산자가 제공된다. 그중 가장 많이 쓰이는 것이 바로 &lt;b&gt;JSON_EXTRACT()&lt;/b&gt; 함수와 &lt;b&gt;-&amp;gt;, -&amp;gt;&amp;gt; 연산자&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sfYi0/btsPBk2toMQ/ctwpqOtcUKcBHZdPBgrkk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sfYi0/btsPBk2toMQ/ctwpqOtcUKcBHZdPBgrkk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sfYi0/btsPBk2toMQ/ctwpqOtcUKcBHZdPBgrkk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsfYi0%2FbtsPBk2toMQ%2FctwpqOtcUKcBHZdPBgrkk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;573&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;396&quot; data-start=&quot;373&quot; data-ke-size=&quot;size26&quot;&gt;1. JSON_EXTRACT 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674683223&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_EXTRACT(json_doc, path)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;527&quot; data-start=&quot;439&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;471&quot; data-start=&quot;439&quot;&gt;json_doc: JSON 형식의 컬럼 또는 문자열&lt;/li&gt;
&lt;li data-end=&quot;527&quot; data-start=&quot;472&quot;&gt;path: 내부 키를 탐색하는 경로 (예: '$.name', '$.items[0]')&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;535&quot; data-start=&quot;529&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674689911&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_EXTRACT('{&quot;name&quot;: &quot;홍길동&quot;, &quot;age&quot;: 30}', '$.name');
-- 결과: &quot;홍길동&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;701&quot; data-start=&quot;623&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;655&quot; data-start=&quot;623&quot;&gt;결과가 &lt;b&gt;JSON 문자열&lt;/b&gt;로 반환됨 (따옴표 포함)&lt;/li&gt;
&lt;li data-end=&quot;701&quot; data-start=&quot;656&quot;&gt;실제 문자열 값으로 쓰려면 -&amp;gt;&amp;gt; 또는 JSON_UNQUOTE() 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;722&quot; data-start=&quot;703&quot; data-ke-size=&quot;size26&quot;&gt;2. -&amp;gt; 와 -&amp;gt;&amp;gt; 연산자 차이&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;907&quot; data-start=&quot;724&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;연산자&lt;/td&gt;
&lt;td&gt;기능&lt;/td&gt;
&lt;td&gt;반환값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;868&quot; data-start=&quot;820&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;829&quot; data-start=&quot;820&quot;&gt;-&amp;gt;&lt;/td&gt;
&lt;td data-end=&quot;858&quot; data-start=&quot;829&quot; data-col-size=&quot;sm&quot;&gt;JSON_EXTRACT와 동일&lt;/td&gt;
&lt;td data-end=&quot;868&quot; data-start=&quot;858&quot; data-col-size=&quot;sm&quot;&gt;JSON 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;907&quot; data-start=&quot;869&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;878&quot; data-start=&quot;869&quot;&gt;-&amp;gt;&amp;gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;899&quot; data-start=&quot;878&quot;&gt;추출된 값을 문자열로 변환&lt;/td&gt;
&lt;td data-end=&quot;907&quot; data-start=&quot;899&quot; data-col-size=&quot;sm&quot;&gt;TEXT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;915&quot; data-start=&quot;909&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674731423&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT '{&quot;name&quot;: &quot;홍길동&quot;}' -&amp;gt; '$.name';
-- 결과: &quot;홍길동&quot; (따옴표 포함)

SELECT '{&quot;name&quot;: &quot;홍길동&quot;}' -&amp;gt;&amp;gt; '$.name';
-- 결과: 홍길동 (순수 문자열)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1065&quot; data-start=&quot;1049&quot; data-ke-size=&quot;size26&quot;&gt;3. 배열 요소 접근하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674738143&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_EXTRACT('[&quot;A&quot;, &quot;B&quot;, &quot;C&quot;]', '$[1]');
-- 결과: &quot;B&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1156&quot; data-start=&quot;1138&quot; data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 연산자도 동일하게 사용 가능:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674763263&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT '[&quot;A&quot;, &quot;B&quot;, &quot;C&quot;]' -&amp;gt;&amp;gt; '$[2]';
-- 결과: C&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1240&quot; data-start=&quot;1216&quot; data-ke-size=&quot;size26&quot;&gt;4. 테이블 내 JSON 컬럼 값 추출&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674772255&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE users (
  id INT,
  profile JSON
);

INSERT INTO users VALUES
(1, '{&quot;name&quot;: &quot;영희&quot;, &quot;age&quot;: 25}'),
(2, '{&quot;name&quot;: &quot;철수&quot;, &quot;age&quot;: 31}');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674778072&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  id,
  profile -&amp;gt;&amp;gt; '$.name' AS 이름,
  profile -&amp;gt; '$.age' AS 나이_JSON,
  profile -&amp;gt;&amp;gt; '$.age' AS 나이_문자열
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1616&quot; data-start=&quot;1530&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1571&quot; data-start=&quot;1530&quot;&gt;-&amp;gt;는 JSON 형식으로 반환되어 &lt;b&gt;정렬이나 비교 연산에 제약&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1616&quot; data-start=&quot;1572&quot;&gt;-&amp;gt;&amp;gt;는 문자열로 변환되어 &lt;b&gt;WHERE 조건이나 LIKE 등에 유리&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1638&quot; data-start=&quot;1618&quot; data-ke-size=&quot;size26&quot;&gt;5. 중첩된 JSON 경로 추출&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674785728&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_EXTRACT(
  '{&quot;user&quot;: {&quot;info&quot;: {&quot;email&quot;: &quot;test@ex.com&quot;}}}',
  '$.user.info.email'
);
-- 결과: &quot;test@ex.com&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674791263&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT '{&quot;user&quot;: {&quot;info&quot;: {&quot;email&quot;: &quot;test@ex.com&quot;}}}' -&amp;gt;&amp;gt; '$.user.info.email';
-- 결과: test@ex.com&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1892&quot; data-start=&quot;1879&quot; data-ke-size=&quot;size26&quot;&gt;6. 실무 활용 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1943&quot; data-start=&quot;1894&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1940&quot; data-start=&quot;1894&quot;&gt;&lt;b&gt;WHERE 조건에서 -&amp;gt;&amp;gt;를 사용&lt;/b&gt;하면 문자열로 비교되어 성능이 안정적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674812296&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM users
WHERE profile -&amp;gt;&amp;gt; '$.name' = '철수';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2094&quot; data-start=&quot;2011&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2058&quot; data-start=&quot;2011&quot;&gt;&lt;b&gt;JSON 컬럼을 직접 조건문에 사용하려면 항상 경로 지정이 명확해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2094&quot; data-start=&quot;2059&quot;&gt;정렬, LIKE, IN 등 문자열 기반 연산에는 -&amp;gt;&amp;gt;를 추천&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2119&quot; data-start=&quot;2096&quot; data-ke-size=&quot;size26&quot;&gt;7. JSON 데이터 존재 여부 확인&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674818807&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_CONTAINS_PATH(profile, 'one', '$.name') FROM users;
-- 결과: 1 (존재), 0 (없음)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2281&quot; data-start=&quot;2219&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2281&quot; data-start=&quot;2219&quot;&gt;JSON_CONTAINS_PATH()와 JSON_CONTAINS()는 필드 존재 여부 체크 시 활용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2308&quot; data-start=&quot;2283&quot; data-ke-size=&quot;size26&quot;&gt;8. 보너스: 값이 없는 경우 대체 처리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674824287&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT IFNULL(profile -&amp;gt;&amp;gt; '$.nickname', '별명없음') AS 닉네임
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2455&quot; data-start=&quot;2389&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2455&quot; data-start=&quot;2389&quot;&gt;존재하지 않는 JSON 키 조회 시 &lt;b&gt;NULL 반환&lt;/b&gt;되므로 IFNULL, COALESCE 등과 함께 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2465&quot; data-start=&quot;2457&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2604&quot; data-start=&quot;2467&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-function-reference.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-function-reference.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2710&quot; data-start=&quot;2622&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>json</category>
      <category>json_extract</category>
      <category>JSON값가져오기</category>
      <category>JSON데이터활용</category>
      <category>JSON연산자</category>
      <category>json쿼리</category>
      <category>MYSQL</category>
      <category>MySQLJSON조회</category>
      <category>MySQL함수</category>
      <category>SQLJSON분석</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1094</guid>
      <comments>https://monkeybusiness.tistory.com/1094#entry1094comment</comments>
      <pubDate>Mon, 28 Jul 2025 15:54:24 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] JSON_OBJECT, JSON_ARRAY로 JSON 생성하기</title>
      <link>https://monkeybusiness.tistory.com/1093</link>
      <description>&lt;p data-end=&quot;376&quot; data-start=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 JSON 데이터를 동적으로 만들기 위해 &lt;b&gt;JSON_OBJECT()&lt;/b&gt;와 &lt;b&gt;JSON_ARRAY()&lt;/b&gt; 함수를 사용할 수 있다. 이 두 함수는 테이블 내 값을 기반으로 동적으로 JSON을 생성하거나, API 응답 형태로 데이터를 구성할 때 매우 유용하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rEJG6/btsPBFZExo8/suSjwYALZfMOosathgtydK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rEJG6/btsPBFZExo8/suSjwYALZfMOosathgtydK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rEJG6/btsPBFZExo8/suSjwYALZfMOosathgtydK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrEJG6%2FbtsPBFZExo8%2FsuSjwYALZfMOosathgtydK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;549&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;400&quot; data-start=&quot;378&quot; data-ke-size=&quot;size26&quot;&gt;1. JSON_OBJECT 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674434759&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_OBJECT(key1, value1, key2, value2, ...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;540&quot; data-start=&quot;459&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;496&quot; data-start=&quot;459&quot;&gt;key와 value를 &lt;b&gt;쌍으로 입력&lt;/b&gt;하여 JSON 객체 생성&lt;/li&gt;
&lt;li data-end=&quot;540&quot; data-start=&quot;497&quot;&gt;key는 문자열, value는 문자열, 숫자, 불리언 등 다양한 타입 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;548&quot; data-start=&quot;542&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674443727&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_OBJECT('name', '노트북', 'price', 1200000);
-- 결과: {&quot;name&quot;: &quot;노트북&quot;, &quot;price&quot;: 1200000}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;672&quot; data-start=&quot;656&quot; data-ke-size=&quot;size23&quot;&gt;테이블 컬럼 기반 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674452919&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_OBJECT('id', id, 'title', title)
FROM posts
WHERE id = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;802&quot; data-start=&quot;756&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;784&quot; data-start=&quot;756&quot;&gt;컬럼 값을 기반으로 동적으로 JSON 생성 가능&lt;/li&gt;
&lt;li data-end=&quot;802&quot; data-start=&quot;785&quot;&gt;API 응답으로 넘기기 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;820&quot; data-start=&quot;804&quot; data-ke-size=&quot;size23&quot;&gt;NULL 포함 시 주의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;875&quot; data-start=&quot;822&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;855&quot; data-start=&quot;822&quot;&gt;값이 NULL이면 자동으로 &quot;key&quot;: null 생성&lt;/li&gt;
&lt;li data-end=&quot;875&quot; data-start=&quot;856&quot;&gt;key가 NULL이면 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674458463&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_OBJECT(NULL, 'test');
-- 결과: NULL + Warning&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;966&quot; data-start=&quot;945&quot; data-ke-size=&quot;size26&quot;&gt;2. JSON_ARRAY 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674465335&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JSON_ARRAY(value1, value2, ...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1043&quot; data-start=&quot;1012&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1043&quot; data-start=&quot;1012&quot;&gt;값만 나열하여 &lt;b&gt;배열(JSON Array)&lt;/b&gt; 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1051&quot; data-start=&quot;1045&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674471111&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_ARRAY('apple', 'banana', 'cherry');
-- 결과: [&quot;apple&quot;, &quot;banana&quot;, &quot;cherry&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1168&quot; data-start=&quot;1150&quot; data-ke-size=&quot;size23&quot;&gt;숫자, 불리언도 포함 가능&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674477655&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_ARRAY(1, 3.14, TRUE, NULL);
-- 결과: [1, 3.14, true, null]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1284&quot; data-start=&quot;1251&quot; data-ke-size=&quot;size26&quot;&gt;3. JSON_OBJECT + JSON_ARRAY 조합&lt;/h2&gt;
&lt;p data-end=&quot;1313&quot; data-start=&quot;1286&quot; data-ke-size=&quot;size16&quot;&gt;복잡한 구조의 JSON도 손쉽게 생성할 수 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674483687&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_OBJECT(
  'id', 101,
  'tags', JSON_ARRAY('mysql', 'json', '함수')
);
-- 결과: {&quot;id&quot;: 101, &quot;tags&quot;: [&quot;mysql&quot;, &quot;json&quot;, &quot;함수&quot;]}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1490&quot; data-start=&quot;1459&quot; data-ke-size=&quot;size26&quot;&gt;4. 실무 예제: 게시글을 JSON 응답으로 만들기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674491271&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  JSON_OBJECT(
    'id', id,
    'title', title,
    'tags', JSON_ARRAY('DB', 'SQL', 'MySQL')
  ) AS json_response
FROM posts
WHERE id = 5;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1711&quot; data-start=&quot;1652&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1682&quot; data-start=&quot;1652&quot;&gt;API 응답용 JSON 문자열을 DB에서 직접 생성&lt;/li&gt;
&lt;li data-end=&quot;1711&quot; data-start=&quot;1683&quot;&gt;애플리케이션에서 추가 가공 없이 바로 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1750&quot; data-start=&quot;1713&quot; data-ke-size=&quot;size26&quot;&gt;5. 배열을 그룹으로 묶어보기 (GROUP_CONCAT 응용)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674500031&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  user_id,
  JSON_ARRAYAGG(tag) AS tag_list
FROM user_tags
GROUP BY user_id;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1920&quot; data-start=&quot;1849&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1887&quot; data-start=&quot;1849&quot;&gt;JSON_ARRAYAGG()는 여러 행을 배열로 묶을 때 사용&lt;/li&gt;
&lt;li data-end=&quot;1920&quot; data-start=&quot;1888&quot;&gt;GROUP_CONCAT()보다 JSON 구조를 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1949&quot; data-start=&quot;1922&quot; data-ke-size=&quot;size26&quot;&gt;6. JSON_OBJECT 사용 시 주의사항&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2124&quot; data-start=&quot;1951&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2038&quot; data-start=&quot;1995&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2009&quot; data-start=&quot;1995&quot;&gt;Key 중복&lt;/td&gt;
&lt;td data-end=&quot;2038&quot; data-start=&quot;2009&quot; data-col-size=&quot;sm&quot;&gt;동일 key 사용 시 가장 마지막 값이 반영됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2085&quot; data-start=&quot;2039&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2053&quot; data-start=&quot;2039&quot;&gt;Key NULL 불가&lt;/td&gt;
&lt;td data-end=&quot;2085&quot; data-start=&quot;2053&quot; data-col-size=&quot;sm&quot;&gt;key에 NULL 들어가면 전체 결과 NULL 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2124&quot; data-start=&quot;2086&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2098&quot; data-start=&quot;2086&quot;&gt;성능 이슈&lt;/td&gt;
&lt;td data-end=&quot;2124&quot; data-start=&quot;2098&quot; data-col-size=&quot;sm&quot;&gt;SELECT 내 다수 호출 시 성능 유의&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2145&quot; data-start=&quot;2126&quot; data-ke-size=&quot;size26&quot;&gt;7. JSON 응답 구조 정리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674528719&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;user&quot;: {
    &quot;id&quot;: 1001,
    &quot;name&quot;: &quot;홍길동&quot;
  },
  &quot;roles&quot;: [&quot;admin&quot;, &quot;editor&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2264&quot; data-start=&quot;2246&quot; data-ke-size=&quot;size16&quot;&gt;이런 형태는 아래처럼 작성 가능:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674539335&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_OBJECT(
  'user', JSON_OBJECT('id', 1001, 'name', '홍길동'),
  'roles', JSON_ARRAY('admin', 'editor')
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2400&quot; data-start=&quot;2392&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2470&quot; data-start=&quot;2402&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2581&quot; data-start=&quot;2488&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>json</category>
      <category>JSON_ARRAY</category>
      <category>JSON_OBJECT</category>
      <category>JSON생성함수</category>
      <category>JSON예제모음</category>
      <category>MYSQL</category>
      <category>MySQLJSON생성</category>
      <category>MySQL함수정리</category>
      <category>SQLJSON응답</category>
      <category>SQL동적JSON</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1093</guid>
      <comments>https://monkeybusiness.tistory.com/1093#entry1093comment</comments>
      <pubDate>Mon, 28 Jul 2025 14:49:56 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] JSON 데이터 타입과 기본 구조 이해하기</title>
      <link>https://monkeybusiness.tistory.com/1092</link>
      <description>&lt;p data-end=&quot;322&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 5.7 버전부터 &lt;b&gt;JSON 데이터 타입&lt;/b&gt;을 공식 지원한다. 이는 단순 문자열이 아닌 &lt;b&gt;구조화된 데이터 형식으로 저장&amp;middot;검색&amp;middot;수정이 가능&lt;/b&gt;하다는 점에서 NoSQL적 유연함을 RDB에 결합한 기능이라 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGIRui/btsPCl7pKZO/nxqAdzLsRYuiKhRKknPnQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGIRui/btsPCl7pKZO/nxqAdzLsRYuiKhRKknPnQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGIRui/btsPCl7pKZO/nxqAdzLsRYuiKhRKknPnQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGIRui%2FbtsPCl7pKZO%2FnxqAdzLsRYuiKhRKknPnQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;549&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;344&quot; data-start=&quot;324&quot; data-ke-size=&quot;size26&quot;&gt;1. JSON 데이터 타입이란?&lt;/h2&gt;
&lt;p data-end=&quot;455&quot; data-start=&quot;346&quot; data-ke-size=&quot;size16&quot;&gt;기존에는 JSON 데이터를 TEXT나 VARCHAR 컬럼에 문자열 형태로 저장했지만, JSON 타입은 &lt;b&gt;MySQL이 내부적으로 구조를 인식하고 최적화된 바이너리 포맷으로 저장&lt;/b&gt;한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674182879&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE products (
  id INT PRIMARY KEY,
  info JSON
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;582&quot; data-start=&quot;530&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;557&quot; data-start=&quot;530&quot;&gt;info 컬럼은 JSON 형식만 저장 가능&lt;/li&gt;
&lt;li data-end=&quot;582&quot; data-start=&quot;558&quot;&gt;유효하지 않은 JSON 형식은 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;595&quot; data-start=&quot;584&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;702&quot; data-start=&quot;597&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;617&quot; data-start=&quot;597&quot;&gt;&lt;b&gt;구조화된 데이터 저장 가능&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;618&quot;&gt;&lt;b&gt;&amp;rarr; 또는 JSON 함수로 세부 데이터 추출 가능&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;675&quot; data-start=&quot;651&quot;&gt;&lt;b&gt;공간 효율적인 바이너리 포맷 저장&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;702&quot; data-start=&quot;676&quot;&gt;&lt;b&gt;인덱싱, 조건문 등 일부 최적화 지원&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;720&quot; data-start=&quot;704&quot; data-ke-size=&quot;size26&quot;&gt;2. JSON 형식 규칙&lt;/h2&gt;
&lt;p data-end=&quot;779&quot; data-start=&quot;722&quot; data-ke-size=&quot;size16&quot;&gt;MySQL JSON 타입에 저장할 수 있는 데이터는 &lt;b&gt;RFC 7159 (JSON 표준)&lt;/b&gt;을 따른다.&lt;/p&gt;
&lt;h3 data-end=&quot;797&quot; data-start=&quot;781&quot; data-ke-size=&quot;size23&quot;&gt;허용되는 JSON 타입&lt;/h3&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1196&quot; data-start=&quot;799&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;타입&lt;/td&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;947&quot; data-start=&quot;897&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;910&quot; data-start=&quot;897&quot;&gt;객체(Object)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;947&quot; data-start=&quot;910&quot;&gt;{&quot;name&quot;: &quot;book&quot;, &quot;price&quot;: 1000}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;997&quot; data-start=&quot;948&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;960&quot; data-start=&quot;948&quot;&gt;배열(Array)&lt;/td&gt;
&lt;td data-end=&quot;997&quot; data-start=&quot;960&quot; data-col-size=&quot;sm&quot;&gt;[&quot;apple&quot;, &quot;banana&quot;, &quot;cherry&quot;]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1046&quot; data-start=&quot;998&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1009&quot; data-start=&quot;998&quot;&gt;문자열&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1046&quot; data-start=&quot;1009&quot;&gt;&quot;Hello&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1096&quot; data-start=&quot;1047&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1059&quot; data-start=&quot;1047&quot;&gt;숫자&lt;/td&gt;
&lt;td data-end=&quot;1096&quot; data-start=&quot;1059&quot; data-col-size=&quot;sm&quot;&gt;42, 3.14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1145&quot; data-start=&quot;1097&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1108&quot; data-start=&quot;1097&quot;&gt;불리언&lt;/td&gt;
&lt;td data-end=&quot;1145&quot; data-start=&quot;1108&quot; data-col-size=&quot;sm&quot;&gt;true, false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1196&quot; data-start=&quot;1146&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1159&quot; data-start=&quot;1146&quot;&gt;널(null)&lt;/td&gt;
&lt;td data-end=&quot;1196&quot; data-start=&quot;1159&quot; data-col-size=&quot;sm&quot;&gt;null&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1220&quot; data-start=&quot;1198&quot; data-ke-size=&quot;size23&quot;&gt;❌ 문자열과 JSON의 혼동 주의&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674204928&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 문자열 저장 (허용)
INSERT INTO products (id, info)
VALUES (1, '{&quot;name&quot;: &quot;펜&quot;, &quot;price&quot;: 500}');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674210752&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- JSON이 아닌 문자열 (에러 발생)
INSERT INTO products (id, info)
VALUES (2, '&quot;name&quot;: &quot;펜&quot;, &quot;price&quot;: 500');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;1468&quot; data-start=&quot;1433&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;1468&quot; data-start=&quot;1435&quot; data-ke-size=&quot;size16&quot;&gt;반드시 &lt;b&gt;전체 구조가 유효한 JSON 형식&lt;/b&gt;이어야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1493&quot; data-start=&quot;1470&quot; data-ke-size=&quot;size26&quot;&gt;3. JSON 컬럼에 데이터 삽입하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674227831&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO products (id, info)
VALUES (3, JSON_OBJECT('name', '노트북', 'price', 1200000));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1615&quot; data-start=&quot;1597&quot; data-ke-size=&quot;size16&quot;&gt;또는 문자열 그대로 삽입도 가능:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674235176&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO products (id, info)
VALUES (4, '{&quot;name&quot;: &quot;모니터&quot;, &quot;price&quot;: 200000}');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1757&quot; data-start=&quot;1709&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1757&quot; data-start=&quot;1709&quot;&gt;JSON_OBJECT()는 내부적으로 유효한 JSON을 생성해주므로 안정적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1781&quot; data-start=&quot;1759&quot; data-ke-size=&quot;size26&quot;&gt;4. JSON 컬럼에서 값 조회하기&lt;/h2&gt;
&lt;p data-end=&quot;1804&quot; data-start=&quot;1783&quot; data-ke-size=&quot;size16&quot;&gt;기본적인 조회는 컬럼 전체를 반환한다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674242904&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT info FROM products WHERE id = 1;
-- 결과: {&quot;name&quot;: &quot;펜&quot;, &quot;price&quot;: 500}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1943&quot; data-start=&quot;1893&quot; data-ke-size=&quot;size16&quot;&gt;JSON 내부 필드 조회는 -&amp;gt;, -&amp;gt;&amp;gt; 또는 JSON_EXTRACT() 사용:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674249216&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT info-&amp;gt;&amp;gt;'$.name' AS 상품명 FROM products;
-- 결과: 펜&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2032&quot; data-start=&quot;2011&quot; data-ke-size=&quot;size26&quot;&gt;5. JSON 데이터 유효성 검사&lt;/h2&gt;
&lt;p data-end=&quot;2062&quot; data-start=&quot;2034&quot; data-ke-size=&quot;size16&quot;&gt;입력 전에 JSON 형식이 맞는지 확인할 수 있다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674255799&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_VALID('{&quot;a&quot;: 1, &quot;b&quot;: 2}');   -- 1 (유효)
SELECT JSON_VALID('&quot;a&quot;: 1, &quot;b&quot;: 2');     -- 0 (유효하지 않음)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;2209&quot; data-start=&quot;2183&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;2209&quot; data-start=&quot;2185&quot; data-ke-size=&quot;size16&quot;&gt;삽입 전 필터링 처리 시 유용하게 활용된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2239&quot; data-start=&quot;2211&quot; data-ke-size=&quot;size26&quot;&gt;6. JSON 저장 시 내부 구조 (바이너리)&lt;/h2&gt;
&lt;p data-end=&quot;2338&quot; data-start=&quot;2241&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 JSON 타입을 문자열로 저장하지 않고, &lt;b&gt;최적화된 binary 포맷&lt;/b&gt;으로 저장한다.&lt;br /&gt;그 덕분에 쿼리 성능도 향상되며, 구조 인식이 가능하다. 예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674266751&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_TYPE(info) FROM products;
-- 결과: OBJECT&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674273176&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT JSON_LENGTH(info) FROM products;
-- 결과: 키 개수 반환&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2494&quot; data-start=&quot;2471&quot; data-ke-size=&quot;size26&quot;&gt;7. JSON 데이터의 기본 제한사항&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2738&quot; data-start=&quot;2496&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;내용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2595&quot; data-start=&quot;2554&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2572&quot; data-start=&quot;2554&quot;&gt;최대 크기&lt;/td&gt;
&lt;td data-end=&quot;2595&quot; data-start=&quot;2572&quot; data-col-size=&quot;sm&quot;&gt;약 1GB (BLOB 한도와 동일)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2636&quot; data-start=&quot;2596&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2614&quot; data-start=&quot;2596&quot;&gt;NULL 저장 여부&lt;/td&gt;
&lt;td data-end=&quot;2636&quot; data-start=&quot;2614&quot; data-col-size=&quot;sm&quot;&gt;JSON 내 null은 저장 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2678&quot; data-start=&quot;2637&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2651&quot; data-start=&quot;2637&quot;&gt;중첩 객체 깊이 제한&lt;/td&gt;
&lt;td data-end=&quot;2678&quot; data-start=&quot;2651&quot; data-col-size=&quot;sm&quot;&gt;100 레벨까지 가능 (버전에 따라 상이)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2738&quot; data-start=&quot;2679&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2696&quot; data-start=&quot;2679&quot;&gt;인덱스 제한&lt;/td&gt;
&lt;td data-end=&quot;2738&quot; data-start=&quot;2696&quot; data-col-size=&quot;sm&quot;&gt;JSON 내부 필드는 일반 인덱스로 불가 (&amp;rarr; 가상 컬럼 사용 필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2754&quot; data-start=&quot;2740&quot; data-ke-size=&quot;size26&quot;&gt;8. 실무 적용 예시&lt;/h2&gt;
&lt;h3 data-end=&quot;2774&quot; data-start=&quot;2756&quot; data-ke-size=&quot;size23&quot;&gt;제품 사양 저장용 JSON&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674291631&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE electronics (
  id INT PRIMARY KEY,
  specs JSON
);

INSERT INTO electronics (id, specs)
VALUES (1, '{&quot;cpu&quot;: &quot;Intel i7&quot;, &quot;ram&quot;: &quot;16GB&quot;, &quot;ssd&quot;: &quot;512GB&quot;}');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2969&quot; data-start=&quot;2956&quot; data-ke-size=&quot;size23&quot;&gt;사용자 맞춤 설정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753674297832&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE user_settings (
  user_id INT,
  config JSON
);

-- 알림 설정 저장
INSERT INTO user_settings (user_id, config)
VALUES (1001, '{&quot;alarm&quot;: true, &quot;newsletter&quot;: false}');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;3215&quot; data-start=&quot;3156&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;3215&quot; data-start=&quot;3158&quot; data-ke-size=&quot;size16&quot;&gt;각각의 사용자의 설정을 유연하게 저장할 수 있어&lt;b&gt; 스키마 변경 없이 다양한 설정 확장이 가능&lt;/b&gt;하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-end=&quot;3225&quot; data-start=&quot;3217&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3343&quot; data-start=&quot;3227&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/json.html#json-data-type&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/json.html#json-data-type&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3447&quot; data-start=&quot;3361&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>json</category>
      <category>JSON객체배열</category>
      <category>JSON기초</category>
      <category>JSON데이터타입</category>
      <category>JSON저장구조</category>
      <category>MYSQL</category>
      <category>mysqljson</category>
      <category>MySQLJSON기능</category>
      <category>MySQL함수</category>
      <category>SQLJSON사용법</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1092</guid>
      <comments>https://monkeybusiness.tistory.com/1092#entry1092comment</comments>
      <pubDate>Mon, 28 Jul 2025 13:46:10 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 암호화와 해시 함수 선택 가이드</title>
      <link>https://monkeybusiness.tistory.com/1091</link>
      <description>&lt;p data-end=&quot;394&quot; data-start=&quot;273&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 다양한 암호화와 해시 함수들을 제공하지만, 이들 함수는 &lt;b&gt;목적, 특성, 보안 수준&lt;/b&gt;이 각각 다르다. 실제 실무에서는 &lt;b&gt;데이터의 특성에 따라 적절한 암호화 또는 해시 방식&lt;/b&gt;을 선택하는 것이 중요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brGECf/btsPCkN7Ogz/JgbKYD9YiHrOjJRrLDbpDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brGECf/btsPCkN7Ogz/JgbKYD9YiHrOjJRrLDbpDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brGECf/btsPCkN7Ogz/JgbKYD9YiHrOjJRrLDbpDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrGECf%2FbtsPCkN7Ogz%2FJgbKYD9YiHrOjJRrLDbpDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;534&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;489&quot; data-start=&quot;473&quot; data-ke-size=&quot;size26&quot;&gt;1. 함수 종류 및 분류&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;942&quot; data-start=&quot;491&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수명&lt;/td&gt;
&lt;td&gt;분류&lt;/td&gt;
&lt;td&gt;복호화 가능&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;675&quot; data-start=&quot;598&quot;&gt;
&lt;td style=&quot;text-align: left;&quot; data-col-size=&quot;sm&quot; data-end=&quot;621&quot; data-start=&quot;598&quot;&gt;&lt;b&gt;PASSWORD()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;633&quot; data-start=&quot;621&quot;&gt;해시&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;647&quot; data-start=&quot;633&quot;&gt;❌&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;675&quot; data-start=&quot;647&quot;&gt;MySQL 전용 비밀번호 해시 (사용 자제)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;746&quot; data-start=&quot;676&quot;&gt;
&lt;td style=&quot;text-align: left;&quot; data-col-size=&quot;sm&quot; data-end=&quot;699&quot; data-start=&quot;676&quot;&gt;&lt;b&gt;MD5(), SHA2()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;711&quot; data-start=&quot;699&quot;&gt;해시&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;725&quot; data-start=&quot;711&quot;&gt;❌&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;746&quot; data-start=&quot;725&quot;&gt;단방향 해시 함수, 비교적 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;813&quot; data-start=&quot;747&quot;&gt;
&lt;td style=&quot;text-align: left;&quot; data-col-size=&quot;sm&quot; data-end=&quot;773&quot; data-start=&quot;747&quot;&gt;&lt;b&gt;ENCODE() / DECODE()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;782&quot; data-start=&quot;773&quot;&gt;대칭 암호화&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;796&quot; data-start=&quot;782&quot;&gt;✅&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;813&quot; data-start=&quot;796&quot;&gt;XOR 기반 간단 암호화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;883&quot; data-start=&quot;814&quot;&gt;
&lt;td style=&quot;text-align: left;&quot; data-col-size=&quot;sm&quot; data-end=&quot;850&quot; data-start=&quot;814&quot;&gt;&lt;b&gt;AES_ENCRYPT() / AES_DECRYPT()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;859&quot; data-start=&quot;850&quot;&gt;대칭 암호화&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;863&quot; data-start=&quot;859&quot;&gt;✅&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;883&quot; data-start=&quot;863&quot;&gt;고급 암호화, 보안 강도 높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;942&quot; data-start=&quot;884&quot;&gt;
&lt;td style=&quot;text-align: left;&quot; data-col-size=&quot;sm&quot; data-end=&quot;916&quot; data-start=&quot;884&quot;&gt;&lt;b&gt;COMPRESS() / UNCOMPRESS()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;924&quot; data-start=&quot;916&quot;&gt;압축/해제&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;928&quot; data-start=&quot;924&quot;&gt;✅&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;942&quot; data-start=&quot;928&quot;&gt;데이터 용량 축소용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;1019&quot; data-start=&quot;944&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;1019&quot; data-start=&quot;946&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 복호화가 필요한가? &amp;rarr; 대칭 암호화 계열 사용.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;✅ 비밀번호, 인증 등 비교만 필요? &amp;rarr; 해시 계열 사용.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1039&quot; data-start=&quot;1021&quot; data-ke-size=&quot;size26&quot;&gt;2. 목적에 따른 추천 함수&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1458&quot; data-start=&quot;1041&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;추천 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1224&quot; data-start=&quot;1170&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1190&quot; data-start=&quot;1170&quot;&gt;사용자 비밀번호 저장&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1224&quot; data-start=&quot;1190&quot;&gt;SHA2(), MD5() (단방향 해시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1283&quot; data-start=&quot;1225&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1245&quot; data-start=&quot;1225&quot;&gt;민감 정보 저장 (복호화 필요)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1283&quot; data-start=&quot;1245&quot;&gt;AES_ENCRYPT(), AES_DECRYPT()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1344&quot; data-start=&quot;1284&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1305&quot; data-start=&quot;1284&quot;&gt;내부 데이터 마스킹&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1344&quot; data-start=&quot;1305&quot;&gt;ENCODE(), DECODE()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1403&quot; data-start=&quot;1345&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1365&quot; data-start=&quot;1345&quot;&gt;로그, 대용량 문자열 압축&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1403&quot; data-start=&quot;1365&quot;&gt;COMPRESS(), UNCOMPRESS()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1458&quot; data-start=&quot;1404&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1424&quot; data-start=&quot;1404&quot;&gt;단순 데이터 무결성 체크&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1458&quot; data-start=&quot;1424&quot;&gt;MD5(), SHA1() 등 해시 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1478&quot; data-start=&quot;1460&quot; data-ke-size=&quot;size26&quot;&gt;3. 각 함수별 장단점 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1943&quot; data-start=&quot;1480&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수&lt;/td&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;단점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1672&quot; data-start=&quot;1603&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1624&quot; data-start=&quot;1603&quot;&gt;MD5() / SHA2()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1652&quot; data-start=&quot;1624&quot;&gt;빠르고 간단, 비교 용이&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1672&quot; data-start=&quot;1652&quot;&gt;복호화 불가, 보안 약점 존재&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1741&quot; data-start=&quot;1673&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1694&quot; data-start=&quot;1673&quot;&gt;AES_ENCRYPT()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1721&quot; data-start=&quot;1694&quot;&gt;보안성 높음, 복호화 가능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1741&quot; data-start=&quot;1721&quot;&gt;키 관리 필요, 느릴 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1800&quot; data-start=&quot;1742&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1763&quot; data-start=&quot;1742&quot;&gt;ENCODE()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1790&quot; data-start=&quot;1763&quot;&gt;사용 간단, 빠른 처리 가능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1800&quot; data-start=&quot;1790&quot;&gt;보안성 낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1873&quot; data-start=&quot;1801&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1822&quot; data-start=&quot;1801&quot;&gt;COMPRESS()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1851&quot; data-start=&quot;1822&quot;&gt;저장 공간 절약 가능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1873&quot; data-start=&quot;1851&quot;&gt;검색 불가, 짧은 데이터에 비효율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1943&quot; data-start=&quot;1874&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1895&quot; data-start=&quot;1874&quot;&gt;PASSWORD()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1925&quot; data-start=&quot;1895&quot;&gt;MySQL 내부에서 자동 적용&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1943&quot; data-start=&quot;1925&quot;&gt;일반 사용 금지 (비권장)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1963&quot; data-start=&quot;1945&quot; data-ke-size=&quot;size26&quot;&gt;4. 실무 활용 시 고려사항&lt;/h2&gt;
&lt;h3 data-end=&quot;1981&quot; data-start=&quot;1965&quot; data-ke-size=&quot;size23&quot;&gt;  대칭키 암호화 시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2091&quot; data-start=&quot;1983&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2019&quot; data-start=&quot;1983&quot;&gt;&lt;b&gt;키 관리가 핵심.&lt;/b&gt; 키가 노출되면 데이터도 바로 유출됨.&lt;/li&gt;
&lt;li data-end=&quot;2063&quot; data-start=&quot;2020&quot;&gt;코드에 키를 하드코딩하지 말고, 환경 변수나 Vault 등을 이용해야 함.&lt;/li&gt;
&lt;li data-end=&quot;2091&quot; data-start=&quot;2064&quot;&gt;키 변경 주기, 재암호화 절차까지 고려할 것.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2110&quot; data-start=&quot;2093&quot; data-ke-size=&quot;size23&quot;&gt;  해시 함수 사용 시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2222&quot; data-start=&quot;2112&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2149&quot; data-start=&quot;2112&quot;&gt;단순한 MD5()보다는 SHA2() 계열이 더 안전하다.&lt;/li&gt;
&lt;li data-end=&quot;2186&quot; data-start=&quot;2150&quot;&gt;비밀번호 해시에는 가능하면 &lt;b&gt;salt&lt;/b&gt;를 함께 적용할 것.&lt;/li&gt;
&lt;li data-end=&quot;2222&quot; data-start=&quot;2187&quot;&gt;단방향이므로 복구 불가능 &amp;rarr; 반드시 비교 기반 처리만 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2241&quot; data-start=&quot;2224&quot; data-ke-size=&quot;size23&quot;&gt;  압축 함수 사용 시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2340&quot; data-start=&quot;2243&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2277&quot; data-start=&quot;2243&quot;&gt;조회 성능보다 &lt;b&gt;저장 공간 최적화&lt;/b&gt;가 우선일 때 적합.&lt;/li&gt;
&lt;li data-end=&quot;2306&quot; data-start=&quot;2278&quot;&gt;자주 조회되거나 검색이 필요한 필드에는 비추천.&lt;/li&gt;
&lt;li data-end=&quot;2340&quot; data-start=&quot;2307&quot;&gt;압축률 테스트를 통해 실제 이득을 확인한 뒤 적용할 것.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2359&quot; data-start=&quot;2342&quot; data-ke-size=&quot;size26&quot;&gt;5. 함수 선택 체크리스트&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2583&quot; data-start=&quot;2361&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2447&quot; data-start=&quot;2361&quot;&gt;복호화가 필요한가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2447&quot; data-start=&quot;2378&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2405&quot; data-start=&quot;2378&quot;&gt;❌ &amp;rarr; 해시 함수 (SHA2, MD5)&lt;/li&gt;
&lt;li data-end=&quot;2447&quot; data-start=&quot;2409&quot;&gt;✅ &amp;rarr; 암호화 함수 (AES_ENCRYPT, ENCODE)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2501&quot; data-start=&quot;2448&quot;&gt;데이터 보안이 중요한가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2501&quot; data-start=&quot;2468&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2501&quot; data-start=&quot;2468&quot;&gt;✅ &amp;rarr; AES_ENCRYPT, SHA2 계열 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2539&quot; data-start=&quot;2502&quot;&gt;데이터가 대용량인가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2539&quot; data-start=&quot;2520&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2539&quot; data-start=&quot;2520&quot;&gt;✅ &amp;rarr; COMPRESS 고려&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2583&quot; data-start=&quot;2540&quot;&gt;마스킹 수준만 필요한가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2583&quot; data-start=&quot;2560&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2583&quot; data-start=&quot;2560&quot;&gt;✅ &amp;rarr; ENCODE로 간단하게 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-end=&quot;2604&quot; data-start=&quot;2585&quot; data-ke-size=&quot;size26&quot;&gt;6. 비밀번호 저장 방식 요약&lt;/h2&gt;
&lt;blockquote data-end=&quot;2634&quot; data-start=&quot;2606&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;2634&quot; data-start=&quot;2608&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❗ 보안이 가장 중요한 케이스: 사용자 비밀번호&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2647&quot; data-start=&quot;2636&quot; data-ke-size=&quot;size16&quot;&gt;✅ 올바른 저장 예:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753667085808&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- SHA2로 해시 처리
INSERT INTO users (username, password_hash)
VALUES ('admin', SHA2('my_password', 256));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2775&quot; data-start=&quot;2764&quot; data-ke-size=&quot;size16&quot;&gt;❌ 잘못된 저장 예:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753667092999&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 평문 저장, 절대 금지
INSERT INTO users (username, password_hash)
VALUES ('admin', 'my_password');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2890&quot; data-start=&quot;2882&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3090&quot; data-start=&quot;2892&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/compression-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/compression-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/password-hashing.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/password-hashing.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3175&quot; data-start=&quot;3108&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>AES암호화</category>
      <category>MYSQL</category>
      <category>mysql보안</category>
      <category>mysql선택가이드</category>
      <category>SHA2</category>
      <category>SQL압축함수</category>
      <category>대칭암호화</category>
      <category>복호화가능</category>
      <category>암호화함수</category>
      <category>해시함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1091</guid>
      <comments>https://monkeybusiness.tistory.com/1091#entry1091comment</comments>
      <pubDate>Mon, 28 Jul 2025 12:45:40 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] COMPRESS와 UNCOMPRESS로 데이터 압축 처리하기</title>
      <link>https://monkeybusiness.tistory.com/1090</link>
      <description>&lt;p data-end=&quot;430&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 COMPRESS()와 UNCOMPRESS() 함수를 통해 &lt;b&gt;데이터를 압축하여 저장하거나 복원하는 기능&lt;/b&gt;을 지원한다. 이 기능은 대용량 텍스트나 바이너리 데이터를 &lt;b&gt;공간 절약&lt;/b&gt;의 목적으로 저장할 때 유용하다. 특히 로그, 메모, 파일 데이터처럼 용량이 큰 필드에서 실무적으로 활용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba5rfV/btsPAWgy23M/kE5XNV18XU4xGF2ikZ3Bgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba5rfV/btsPAWgy23M/kE5XNV18XU4xGF2ikZ3Bgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba5rfV/btsPAWgy23M/kE5XNV18XU4xGF2ikZ3Bgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba5rfV%2FbtsPAWgy23M%2FkE5XNV18XU4xGF2ikZ3Bgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;524&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;451&quot; data-start=&quot;432&quot; data-ke-size=&quot;size26&quot;&gt;1. COMPRESS 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666761583&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TO_BASE64(COMPRESS('압축할 텍스트 데이터'));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;626&quot; data-start=&quot;508&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;545&quot; data-start=&quot;508&quot;&gt;입력된 문자열을 &lt;b&gt;zlib 라이브러리를 기반으로 압축&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;582&quot; data-start=&quot;546&quot;&gt;결과는 바이너리(BLOB)로 반환되므로, 사람이 읽기 어렵다.&lt;/li&gt;
&lt;li data-end=&quot;626&quot; data-start=&quot;583&quot;&gt;이를 저장하거나 조회 시에는 BASE64로 인코딩하는 것이 일반적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;640&quot; data-start=&quot;628&quot; data-ke-size=&quot;size23&quot;&gt;압축 결과 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666767455&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LENGTH('압축할 데이터'), LENGTH(COMPRESS('압축할 데이터'));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;763&quot; data-start=&quot;709&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;734&quot; data-start=&quot;709&quot;&gt;원래 데이터가 클수록 압축 효과가 커진다.&lt;/li&gt;
&lt;li data-end=&quot;763&quot; data-start=&quot;735&quot;&gt;&lt;b&gt;짧은 문자열은 오히려 길어질 수도 있다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;786&quot; data-start=&quot;765&quot; data-ke-size=&quot;size26&quot;&gt;2. UNCOMPRESS 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666772543&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SET @compressed = TO_BASE64(COMPRESS('MySQL 데이터 압축'));
SELECT UNCOMPRESS(FROM_BASE64(@compressed));
-- 결과: MySQL 데이터 압축&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;938&quot; data-start=&quot;846&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;873&quot; data-start=&quot;846&quot;&gt;COMPRESS()로 압축된 데이터를 복원&lt;/li&gt;
&lt;li data-end=&quot;894&quot; data-start=&quot;874&quot;&gt;원래의 문자열로 되돌릴 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;938&quot; data-start=&quot;895&quot;&gt;FROM_BASE64()로 디코딩한 뒤 UNCOMPRESS() 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;949&quot; data-start=&quot;940&quot; data-ke-size=&quot;size23&quot;&gt;복원 예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666858439&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SET @compressed = TO_BASE64(COMPRESS('MySQL 데이터 압축'));
SELECT UNCOMPRESS(FROM_BASE64(@compressed));
-- 결과: MySQL 데이터 압축&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1097&quot; data-start=&quot;1083&quot; data-ke-size=&quot;size26&quot;&gt;3. 실무 활용 예시&lt;/h2&gt;
&lt;h3 data-end=&quot;1112&quot; data-start=&quot;1099&quot; data-ke-size=&quot;size23&quot;&gt;대용량 로그 저장&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666863951&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO log_data (created_at, log_blob)
VALUES (NOW(), COMPRESS('에러 메시지와 긴 로그 정보...'));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1231&quot; data-start=&quot;1218&quot; data-ke-size=&quot;size23&quot;&gt;압축된 로그 복원&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666872551&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT created_at, UNCOMPRESS(log_blob) AS log_text
FROM log_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1388&quot; data-start=&quot;1312&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1361&quot; data-start=&quot;1312&quot;&gt;log_blob 컬럼 타입은 &lt;b&gt;BLOB&lt;/b&gt; 또는 &lt;b&gt;MEDIUMBLOB&lt;/b&gt; 권장&lt;/li&gt;
&lt;li data-end=&quot;1388&quot; data-start=&quot;1362&quot;&gt;압축 비율이 높을수록 저장 공간이 줄어든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1405&quot; data-start=&quot;1390&quot; data-ke-size=&quot;size26&quot;&gt;4. 압축 효과 테스트&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666877864&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  LENGTH(REPEAT('1234567890', 1000)) AS 원본길이,
  LENGTH(COMPRESS(REPEAT('1234567890', 1000))) AS 압축길이;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1600&quot; data-start=&quot;1529&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1569&quot; data-start=&quot;1529&quot;&gt;반복 문자열이나 유사 패턴이 많을수록 &lt;b&gt;압축률은 크게 증가&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;1600&quot; data-start=&quot;1570&quot;&gt;일반 텍스트는 보통 50~80% 수준까지 줄어든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1612&quot; data-start=&quot;1602&quot; data-ke-size=&quot;size26&quot;&gt;5. 주의사항&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1860&quot; data-start=&quot;1614&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;내용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1710&quot; data-start=&quot;1666&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1681&quot; data-start=&quot;1666&quot;&gt;문자셋 호환&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1710&quot; data-start=&quot;1681&quot;&gt;압축 결과는 바이너리이므로 인코딩 깨짐에 유의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1768&quot; data-start=&quot;1711&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1727&quot; data-start=&quot;1711&quot;&gt;검색 불가&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1768&quot; data-start=&quot;1727&quot;&gt;압축된 데이터는 &lt;b&gt;LIKE, FULLTEXT&lt;/b&gt; 등 검색이 불가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1813&quot; data-start=&quot;1769&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1782&quot; data-start=&quot;1769&quot;&gt;짧은 데이터 비효율&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1813&quot; data-start=&quot;1782&quot;&gt;압축 오버헤드 때문에 짧은 데이터는 오히려 비효율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1860&quot; data-start=&quot;1814&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1828&quot; data-start=&quot;1814&quot;&gt;읽기 성능 영향&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1860&quot; data-start=&quot;1828&quot;&gt;매번 UNCOMPRESS 할 경우 쿼리 성능에 부담&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;1919&quot; data-start=&quot;1862&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;1919&quot; data-start=&quot;1864&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;즉시 조회가 잦은 필드에는 사용하지 않는 것이 좋다.&lt;/b&gt; 로그나 보관성 데이터에 적합하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-end=&quot;1953&quot; data-start=&quot;1921&quot; data-ke-size=&quot;size26&quot;&gt;6. COMPRESS vs AES_ENCRYPT 차이&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2324&quot; data-start=&quot;1955&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;COMPRESS&lt;/td&gt;
&lt;td&gt;AES_ENCRYPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2148&quot; data-start=&quot;2090&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2107&quot; data-start=&quot;2090&quot;&gt;목적&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2125&quot; data-start=&quot;2107&quot;&gt;&lt;b&gt;용량 축소&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2148&quot; data-start=&quot;2125&quot;&gt;&lt;b&gt;데이터 보안&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2211&quot; data-start=&quot;2149&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2163&quot; data-start=&quot;2149&quot;&gt;복호화 여부&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2184&quot; data-start=&quot;2163&quot;&gt;O (UNCOMPRESS)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2211&quot; data-start=&quot;2184&quot;&gt;O (AES_DECRYPT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2275&quot; data-start=&quot;2212&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2226&quot; data-start=&quot;2212&quot;&gt;암호화 기능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2247&quot; data-start=&quot;2226&quot;&gt;X&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2275&quot; data-start=&quot;2247&quot;&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2324&quot; data-start=&quot;2276&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2291&quot; data-start=&quot;2276&quot;&gt;사용 사례&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2305&quot; data-start=&quot;2291&quot;&gt;로그, 대용량 데이터&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2324&quot; data-start=&quot;2305&quot;&gt;개인정보, 인증 정보 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2334&quot; data-start=&quot;2326&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2507&quot; data-start=&quot;2336&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_compress&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_compress&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_uncompress&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_uncompress&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2614&quot; data-start=&quot;2525&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>BLOB데이터처리</category>
      <category>COMPRESS</category>
      <category>DB공간절약</category>
      <category>MYSQL</category>
      <category>MySQL바이너리처리</category>
      <category>MySQL압축</category>
      <category>MySQL함수정리</category>
      <category>sql성능최적화</category>
      <category>SQL압축복원</category>
      <category>uncompress</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1090</guid>
      <comments>https://monkeybusiness.tistory.com/1090#entry1090comment</comments>
      <pubDate>Mon, 28 Jul 2025 11:42:39 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] ENCODE와 DECODE 함수 사용법  </title>
      <link>https://monkeybusiness.tistory.com/1089</link>
      <description>&lt;p data-end=&quot;403&quot; data-start=&quot;243&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 제공하는 간단한 대칭 암호화 함수인 ENCODE()와 DECODE()는 비교적 오래된 방식이지만, 간단한 문자열 암호화에 여전히 사용되고 있다. 보안 수준은 높지 않지만 &lt;b&gt;내부 시스템 데이터 보호&lt;/b&gt;, &lt;b&gt;간단한 식별자 마스킹&lt;/b&gt; 등 용도에 따라 활용이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgSl3E/btsPBltr7z6/CmqpSzRdXugDkmcPkLD6Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgSl3E/btsPBltr7z6/CmqpSzRdXugDkmcPkLD6Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgSl3E/btsPBltr7z6/CmqpSzRdXugDkmcPkLD6Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgSl3E%2FbtsPBltr7z6%2FCmqpSzRdXugDkmcPkLD6Ek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;534&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;422&quot; data-start=&quot;405&quot; data-ke-size=&quot;size26&quot;&gt;1. ENCODE 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666635623&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TO_BASE64(ENCODE('mysqltest', 'mysecretkey'));
-- 결과 예시: QNLfB0lTAA1aBA==&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;665&quot; data-start=&quot;517&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;595&quot; data-start=&quot;517&quot;&gt;ENCODE(str, pass_str)
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;595&quot; data-start=&quot;545&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;562&quot; data-start=&quot;545&quot;&gt;str: 암호화할 문자열&lt;/li&gt;
&lt;li data-end=&quot;595&quot; data-start=&quot;565&quot;&gt;pass_str: 대칭키 역할을 하는 키 문자열&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;665&quot; data-start=&quot;596&quot;&gt;암호화된 결과는 &lt;b&gt;바이너리&lt;/b&gt; 형식이므로 반드시 TO_BASE64() 등으로 인코딩해야 저장하거나 확인이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;684&quot; data-start=&quot;667&quot; data-ke-size=&quot;size26&quot;&gt;2. DECODE 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666644303&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DECODE(FROM_BASE64('QNLfB0lTAA1aBA=='), 'mysecretkey');
-- 결과: mysqltest&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;926&quot; data-start=&quot;778&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;871&quot; data-start=&quot;778&quot;&gt;DECODE(crypt_str, pass_str)
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;871&quot; data-start=&quot;812&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;840&quot; data-start=&quot;812&quot;&gt;crypt_str: 암호화된 바이너리 문자열&lt;/li&gt;
&lt;li data-end=&quot;871&quot; data-start=&quot;843&quot;&gt;pass_str: 암호화에 사용한 동일한 키&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;926&quot; data-start=&quot;872&quot;&gt;복호화할 때는 암호화에 사용한 &lt;b&gt;정확히 같은 키 문자열&lt;/b&gt;을 입력해야 올바른 결과가 나온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;955&quot; data-start=&quot;928&quot; data-ke-size=&quot;size26&quot;&gt;3. ENCODE / DECODE 기본 예제&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666650583&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 암호화
SELECT TO_BASE64(ENCODE('123456-7890123', 'secureKey')) AS 암호문;

-- 복호화
SELECT DECODE(FROM_BASE64('암호문'), 'secureKey') AS 원본값;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1192&quot; data-start=&quot;1103&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1192&quot; data-start=&quot;1103&quot;&gt;실제 저장 시에는 암호화된 값을 VARBINARY, BLOB 형식의 컬럼에 저장하거나, BASE64로 인코딩해서 문자열로 저장하면 관리가 편하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1209&quot; data-start=&quot;1194&quot; data-ke-size=&quot;size26&quot;&gt;4. 테이블에 적용하기&lt;/h2&gt;
&lt;h3 data-end=&quot;1221&quot; data-start=&quot;1211&quot; data-ke-size=&quot;size23&quot;&gt;암호화 저장&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666660135&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO member_data (user_id, encrypted_name)
VALUES ('kim123', TO_BASE64(ENCODE('김철수', 'simpleKey')));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1353&quot; data-start=&quot;1343&quot; data-ke-size=&quot;size23&quot;&gt;복호화 조회&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753666666199&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  user_id,
  DECODE(FROM_BASE64(encrypted_name), 'simpleKey') AS real_name
FROM member_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1505&quot; data-start=&quot;1468&quot; data-ke-size=&quot;size26&quot;&gt;5. ENCODE/DECODE vs AES_ENCRYPT 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2018&quot; data-start=&quot;1507&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;ENCODE/DECODE&lt;/td&gt;
&lt;td&gt;AES_ENCRYPT/AES_DECRYPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1733&quot; data-start=&quot;1670&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1682&quot; data-start=&quot;1670&quot;&gt;암호화 수준&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1706&quot; data-start=&quot;1682&quot;&gt;낮음 (간단한 XOR 방식)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1733&quot; data-start=&quot;1706&quot;&gt;강력한 블록 암호화 (AES 표준)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1811&quot; data-start=&quot;1734&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1746&quot; data-start=&quot;1734&quot;&gt;복호화 가능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1775&quot; data-start=&quot;1746&quot;&gt;O&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1811&quot; data-start=&quot;1775&quot;&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1877&quot; data-start=&quot;1812&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1826&quot; data-start=&quot;1812&quot;&gt;키 관리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1851&quot; data-start=&quot;1826&quot;&gt;평문 문자열&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1877&quot; data-start=&quot;1851&quot;&gt;바이트 길이 기준 키 관리 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1941&quot; data-start=&quot;1878&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1891&quot; data-start=&quot;1878&quot;&gt;권장 용도&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1912&quot; data-start=&quot;1891&quot;&gt;내부 마스킹용, 빠른 처리용&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1941&quot; data-start=&quot;1912&quot;&gt;민감 정보 보호용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2018&quot; data-start=&quot;1942&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1956&quot; data-start=&quot;1942&quot;&gt;안전성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1984&quot; data-start=&quot;1956&quot;&gt;낮음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2018&quot; data-start=&quot;1984&quot;&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;2084&quot; data-start=&quot;2020&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;2084&quot; data-start=&quot;2022&quot; data-ke-size=&quot;size16&quot;&gt;✅ ENCODE/DECODE는 실질적인 보안을 위한 암호화보다는 간단한 난독화 수준으로만 사용해야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-end=&quot;2102&quot; data-start=&quot;2086&quot; data-ke-size=&quot;size26&quot;&gt;6. 실무에서의 활용 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2187&quot; data-start=&quot;2104&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2131&quot; data-start=&quot;2104&quot;&gt;&lt;b&gt;관리자용 내부 시스템에서 식별자 마스킹&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2158&quot; data-start=&quot;2132&quot;&gt;&lt;b&gt;로그 기록 시 민감 정보 간접 암호화&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2187&quot; data-start=&quot;2159&quot;&gt;&lt;b&gt;일정 기간 후 파기될 데이터 암호화 처리&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;2254&quot; data-start=&quot;2189&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;2254&quot; data-start=&quot;2191&quot; data-ke-size=&quot;size16&quot;&gt;단, 외부에 노출되거나 장기 보관되는 정보는 AES_ENCRYPT 또는 SHA2 기반 방식 사용이 필수다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-end=&quot;2274&quot; data-start=&quot;2256&quot; data-ke-size=&quot;size26&quot;&gt;7. 문자셋 인코딩 주의사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2408&quot; data-start=&quot;2276&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2350&quot; data-start=&quot;2276&quot;&gt;ENCODE()/DECODE()는 내부적으로 &lt;b&gt;XOR 연산 기반&lt;/b&gt;이기 때문에 문자셋에 따라 &lt;b&gt;결과가 깨질 수 있음&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2408&quot; data-start=&quot;2351&quot;&gt;대부분의 경우 utf8mb4 설정을 유지하고, BASE64로 저장하는 방식이 가장 안전하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2418&quot; data-start=&quot;2410&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2585&quot; data-start=&quot;2420&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_encode&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_encode&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_decode&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_decode&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2677&quot; data-start=&quot;2603&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>decode</category>
      <category>encode</category>
      <category>MYSQL</category>
      <category>mysql보안</category>
      <category>MySQL복호화</category>
      <category>MySQL암호화</category>
      <category>SQL암호화함수</category>
      <category>XOR암호화</category>
      <category>간단암호화</category>
      <category>문자열암호화</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1089</guid>
      <comments>https://monkeybusiness.tistory.com/1089#entry1089comment</comments>
      <pubDate>Mon, 28 Jul 2025 10:38:25 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] AES_ENCRYPT, AES_DECRYPT로 대칭키 암호화  </title>
      <link>https://monkeybusiness.tistory.com/1088</link>
      <description>&lt;p data-end=&quot;437&quot; data-start=&quot;266&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 가장 널리 사용되는 &lt;b&gt;양방향 대칭키 암호화 함수&lt;/b&gt;는 AES_ENCRYPT()와 AES_DECRYPT()이다. 이 함수는 데이터를 암호화해서 안전하게 저장하고, 필요 시 복호화할 수 있다는 점에서 &lt;b&gt;개인정보, 인증 정보, 금융 데이터 처리 등 민감한 데이터를 다룰 때 유용하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;499&quot; data-start=&quot;439&quot; data-ke-size=&quot;size16&quot;&gt;단방향 해시 함수와 달리, &lt;b&gt;암호화된 데이터를 원래 값으로 되돌릴 수 있다는 점&lt;/b&gt;이 가장 큰 차이점이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WDx0e/btsPxlnJxDi/8jqgKh2SVVKil1RFE3520k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WDx0e/btsPxlnJxDi/8jqgKh2SVVKil1RFE3520k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WDx0e/btsPxlnJxDi/8jqgKh2SVVKil1RFE3520k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWDx0e%2FbtsPxlnJxDi%2F8jqgKh2SVVKil1RFE3520k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;548&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;523&quot; data-start=&quot;501&quot; data-ke-size=&quot;size26&quot;&gt;1. AES_ENCRYPT 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408468027&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TO_BASE64(AES_ENCRYPT('secret', 'mykey')) AS 암호문;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;731&quot; data-start=&quot;594&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;613&quot; data-start=&quot;594&quot;&gt;첫 번째 인자: 암호화할 문자열&lt;/li&gt;
&lt;li data-end=&quot;637&quot; data-start=&quot;614&quot;&gt;두 번째 인자: &lt;b&gt;대칭키(비밀키)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;688&quot; data-start=&quot;638&quot;&gt;결과는 바이너리이므로 가공 없이 바로 출력하면 깨짐 &amp;rarr; &lt;b&gt;BASE64 인코딩&lt;/b&gt; 필요&lt;/li&gt;
&lt;li data-end=&quot;731&quot; data-start=&quot;689&quot;&gt;AES-128, AES-256 방식은 &lt;b&gt;키 길이&lt;/b&gt;에 따라 자동 적용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;755&quot; data-start=&quot;733&quot; data-ke-size=&quot;size26&quot;&gt;2. AES_DECRYPT 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408473567&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT AES_DECRYPT(FROM_BASE64('암호문'), 'mykey');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;933&quot; data-start=&quot;818&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;844&quot; data-start=&quot;818&quot;&gt;암호화된 데이터를 &lt;b&gt;원래 값으로 복호화&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;883&quot; data-start=&quot;845&quot;&gt;암호화에 사용된 키와 동일한 키를 사용해야 정상적으로 복호화된다.&lt;/li&gt;
&lt;li data-end=&quot;933&quot; data-start=&quot;884&quot;&gt;BASE64로 인코딩된 암호문은 FROM_BASE64()로 다시 디코딩한 뒤 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;951&quot; data-start=&quot;935&quot; data-ke-size=&quot;size26&quot;&gt;3. 기본 암복호화 예제&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408482983&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 암호화
SELECT TO_BASE64(AES_ENCRYPT('민감정보', 'key1234')) AS enc;

-- 복호화
SELECT AES_DECRYPT(FROM_BASE64('암호문'), 'key1234') AS 복호화결과;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1199&quot; data-start=&quot;1097&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1130&quot; data-start=&quot;1097&quot;&gt;암호문을 직접 복호화해보면 바이너리 &amp;rarr; 문자열 처리 필요&lt;/li&gt;
&lt;li data-end=&quot;1199&quot; data-start=&quot;1131&quot;&gt;AES_DECRYPT() 결과도 바이너리이므로 &lt;b&gt;CAST 또는 CONVERT로 문자형 처리&lt;/b&gt;가 필요할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408488479&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONVERT(AES_DECRYPT(FROM_BASE64('암호문'), 'key1234') USING utf8) AS 복호화;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1306&quot; data-start=&quot;1291&quot; data-ke-size=&quot;size26&quot;&gt;4. 테이블에 적용하기&lt;/h2&gt;
&lt;h3 data-end=&quot;1324&quot; data-start=&quot;1308&quot; data-ke-size=&quot;size23&quot;&gt;사용자 정보 저장 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408496255&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO secure_users (username, encrypted_phone)
VALUES (
  'user01',
  TO_BASE64(AES_ENCRYPT('01012345678', 'secureKey!'))
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1479&quot; data-start=&quot;1469&quot; data-ke-size=&quot;size23&quot;&gt;복호화 조회&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408501783&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  username,
  CONVERT(AES_DECRYPT(FROM_BASE64(encrypted_phone), 'secureKey!') USING utf8) AS phone
FROM secure_users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1669&quot; data-start=&quot;1619&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1669&quot; data-start=&quot;1619&quot;&gt;데이터베이스에 저장할 때는 BLOB 또는 VARBINARY 컬럼 타입 사용 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1691&quot; data-start=&quot;1671&quot; data-ke-size=&quot;size26&quot;&gt;5. 실무 팁: 키 관리가 핵심&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1871&quot; data-start=&quot;1693&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1766&quot; data-start=&quot;1693&quot;&gt;AES_ENCRYPT()와 AES_DECRYPT()는 모두 &lt;b&gt;대칭키 기반&lt;/b&gt;이므로 키가 노출되면 데이터도 쉽게 복호화됨&lt;/li&gt;
&lt;li data-end=&quot;1844&quot; data-start=&quot;1767&quot;&gt;키는 코드에 직접 넣기보다는 환경변수, Vault, Config Server 등을 통해 &lt;b&gt;보안 영역에서 분리 관리&lt;/b&gt;하는 것이 필수다&lt;/li&gt;
&lt;li data-end=&quot;1871&quot; data-start=&quot;1845&quot;&gt;키 교체 시에는 재암호화 작업도 고려해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1894&quot; data-start=&quot;1873&quot; data-ke-size=&quot;size26&quot;&gt;6. AES 암호화 시 주의할 점&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2269&quot; data-start=&quot;1896&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;주의사항&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2066&quot; data-start=&quot;1978&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2010&quot; data-start=&quot;1978&quot;&gt;키 길이&lt;/td&gt;
&lt;td data-end=&quot;2066&quot; data-start=&quot;2010&quot; data-col-size=&quot;md&quot;&gt;16, 24, 32바이트로 맞추는 것이 좋다 (AES-128, AES-192, AES-256)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2134&quot; data-start=&quot;2067&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2096&quot; data-start=&quot;2067&quot;&gt;바이너리 처리&lt;/td&gt;
&lt;td data-end=&quot;2134&quot; data-start=&quot;2096&quot; data-col-size=&quot;md&quot;&gt;결과는 바이너리로 나오므로 반드시 BASE64 인코딩 후 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2211&quot; data-start=&quot;2135&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2165&quot; data-start=&quot;2135&quot;&gt;문자셋 충돌&lt;/td&gt;
&lt;td data-end=&quot;2211&quot; data-start=&quot;2165&quot; data-col-size=&quot;md&quot;&gt;utf8, euckr 등의 문자셋에 따라 복호화 결과가 깨질 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2269&quot; data-start=&quot;2212&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2241&quot; data-start=&quot;2212&quot;&gt;키 노출 위험&lt;/td&gt;
&lt;td data-end=&quot;2269&quot; data-start=&quot;2241&quot; data-col-size=&quot;md&quot;&gt;하드코딩은 금물. 반드시 보안 저장소를 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2292&quot; data-start=&quot;2271&quot; data-ke-size=&quot;size26&quot;&gt;7. 암호화 대상 필드 추천 예시&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2363&quot; data-start=&quot;2294&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2306&quot; data-start=&quot;2294&quot;&gt;&lt;b&gt;주민등록번호&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2319&quot; data-start=&quot;2307&quot;&gt;&lt;b&gt;휴대폰 번호&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2332&quot; data-start=&quot;2320&quot;&gt;&lt;b&gt;이메일 주소&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2347&quot; data-start=&quot;2333&quot;&gt;&lt;b&gt;결제 관련 정보&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2363&quot; data-start=&quot;2348&quot;&gt;&lt;b&gt;API 키, 토큰&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2380&quot; data-start=&quot;2365&quot; data-ke-size=&quot;size26&quot;&gt;8. SHA2와의 차이&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2679&quot; data-start=&quot;2382&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;AES_ENCRYPT&lt;/td&gt;
&lt;td&gt;SHA2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2568&quot; data-start=&quot;2517&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2529&quot; data-start=&quot;2517&quot;&gt;암호화 방식&lt;/td&gt;
&lt;td data-end=&quot;2547&quot; data-start=&quot;2529&quot; data-col-size=&quot;sm&quot;&gt;&lt;b&gt;양방향(복호화 가능)&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;2568&quot; data-start=&quot;2547&quot; data-col-size=&quot;sm&quot;&gt;단방향 (복호화 불가)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2621&quot; data-start=&quot;2569&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2582&quot; data-start=&quot;2569&quot;&gt;사용 목적&lt;/td&gt;
&lt;td data-end=&quot;2603&quot; data-start=&quot;2582&quot; data-col-size=&quot;sm&quot;&gt;민감 정보 저장, 복호화 필요 시&lt;/td&gt;
&lt;td data-end=&quot;2621&quot; data-start=&quot;2603&quot; data-col-size=&quot;sm&quot;&gt;비밀번호 저장, 인증 목적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2679&quot; data-start=&quot;2622&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2634&quot; data-start=&quot;2622&quot;&gt;키 필요 여부&lt;/td&gt;
&lt;td data-end=&quot;2655&quot; data-start=&quot;2634&quot; data-col-size=&quot;sm&quot;&gt;필요&lt;/td&gt;
&lt;td data-end=&quot;2679&quot; data-start=&quot;2655&quot; data-col-size=&quot;sm&quot;&gt;필요 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2689&quot; data-start=&quot;2681&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2866&quot; data-start=&quot;2691&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-encrypt&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-encrypt&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-decrypt&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-decrypt&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2970&quot; data-start=&quot;2884&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>aes_decrypt</category>
      <category>aes_encrypt</category>
      <category>DB보안</category>
      <category>MYSQL</category>
      <category>MySQL보안키관리</category>
      <category>MySQL복호화</category>
      <category>MySQL암호화</category>
      <category>SQL암호화예제</category>
      <category>민감정보보호</category>
      <category>양방향암호화</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1088</guid>
      <comments>https://monkeybusiness.tistory.com/1088#entry1088comment</comments>
      <pubDate>Fri, 25 Jul 2025 18:50:20 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] MD5와 SHA 해시 함수 비교와 실전 활용</title>
      <link>https://monkeybusiness.tistory.com/1087</link>
      <description>&lt;p data-end=&quot;357&quot; data-start=&quot;203&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 제공하는 대표적인 해시 함수는 &lt;b&gt;MD5()&lt;/b&gt;와 &lt;b&gt;SHA1()&lt;/b&gt;, &lt;b&gt;SHA2()&lt;/b&gt; 시리즈다. 이 함수들은 텍스트를 고정 길이의 해시값으로 변환해 &lt;b&gt;데이터 위변조 감지, 인증, 무결성 검증 등에 활용&lt;/b&gt;된다. 하지만 보안 수준과 용도에 따라 선택이 매우 중요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EV4TP/btsPyenMC83/f8lqRj3rS2LM6lTHhUKzkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EV4TP/btsPyenMC83/f8lqRj3rS2LM6lTHhUKzkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EV4TP/btsPyenMC83/f8lqRj3rS2LM6lTHhUKzkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEV4TP%2FbtsPyenMC83%2Ff8lqRj3rS2LM6lTHhUKzkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;534&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;373&quot; data-start=&quot;359&quot; data-ke-size=&quot;size26&quot;&gt;1. MD5 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408266879&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT MD5('mypassword');
-- 결과: 34819d7beeabb9260a5c854bc85b3e44&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;569&quot; data-start=&quot;453&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;478&quot; data-start=&quot;453&quot;&gt;&lt;b&gt;128비트(16바이트)&lt;/b&gt; 해시를 생성&lt;/li&gt;
&lt;li data-end=&quot;501&quot; data-start=&quot;479&quot;&gt;32자리 소문자 16진수 문자열 반환&lt;/li&gt;
&lt;li data-end=&quot;534&quot; data-start=&quot;502&quot;&gt;&lt;b&gt;빠르고 가볍지만, 충돌 가능성 높아 보안성 낮음&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;569&quot; data-start=&quot;535&quot;&gt;여전히 &lt;b&gt;파일 무결성 체크, 캐시 키 생성&lt;/b&gt; 등에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;586&quot; data-start=&quot;571&quot; data-ke-size=&quot;size26&quot;&gt;2. SHA 함수 종류&lt;/h2&gt;
&lt;h3 data-end=&quot;598&quot; data-start=&quot;588&quot; data-ke-size=&quot;size23&quot;&gt;SHA1()&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408275935&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SHA1('mypassword');
-- 결과: a7e017cfd0f3ca3b45f18cf1db4ef5baec6ecb82&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;747&quot; data-start=&quot;687&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;711&quot; data-start=&quot;687&quot;&gt;&lt;b&gt;160비트(20바이트)&lt;/b&gt; 해시 생성&lt;/li&gt;
&lt;li data-end=&quot;747&quot; data-start=&quot;712&quot;&gt;보안성은 MD5보다 우수하지만, &lt;b&gt;이미 충돌 사례 존재&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;759&quot; data-start=&quot;749&quot; data-ke-size=&quot;size23&quot;&gt;SHA2()&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408283175&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SHA2('mypassword', 256);
-- 결과: 89b4f314dc44d38a2ab99945cebc674c41d90d92345bb229a0fba310820f5d98&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;983&quot; data-start=&quot;877&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;906&quot; data-start=&quot;877&quot;&gt;SHA2(str, hash_length) 형식&lt;/li&gt;
&lt;li data-end=&quot;950&quot; data-start=&quot;907&quot;&gt;hash_length는 224, 256, 384, 512 중 선택 가능&lt;/li&gt;
&lt;li data-end=&quot;983&quot; data-start=&quot;951&quot;&gt;가장 많이 쓰는 값은 &lt;b&gt;SHA2(str, 256)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1014&quot; data-start=&quot;985&quot; data-ke-size=&quot;size26&quot;&gt;3. MD5 vs SHA1 vs SHA2 비교표&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1420&quot; data-start=&quot;1016&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수명&lt;/td&gt;
&lt;td&gt;길이 (bit)&lt;/td&gt;
&lt;td&gt;결과 길이&lt;/td&gt;
&lt;td&gt;보안성&lt;/td&gt;
&lt;td&gt;비고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1225&quot; data-start=&quot;1159&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1170&quot; data-start=&quot;1159&quot;&gt;MD5&lt;/td&gt;
&lt;td data-end=&quot;1183&quot; data-start=&quot;1170&quot; data-col-size=&quot;sm&quot;&gt;128&lt;/td&gt;
&lt;td data-end=&quot;1195&quot; data-start=&quot;1183&quot; data-col-size=&quot;sm&quot;&gt;32자&lt;/td&gt;
&lt;td data-end=&quot;1206&quot; data-start=&quot;1195&quot; data-col-size=&quot;sm&quot;&gt;낮음&lt;/td&gt;
&lt;td data-end=&quot;1225&quot; data-start=&quot;1206&quot; data-col-size=&quot;sm&quot;&gt;빠르지만 충돌 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1291&quot; data-start=&quot;1226&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1237&quot; data-start=&quot;1226&quot;&gt;SHA1&lt;/td&gt;
&lt;td data-end=&quot;1250&quot; data-start=&quot;1237&quot; data-col-size=&quot;sm&quot;&gt;160&lt;/td&gt;
&lt;td data-end=&quot;1262&quot; data-start=&quot;1250&quot; data-col-size=&quot;sm&quot;&gt;40자&lt;/td&gt;
&lt;td data-end=&quot;1273&quot; data-start=&quot;1262&quot; data-col-size=&quot;sm&quot;&gt;중간&lt;/td&gt;
&lt;td data-end=&quot;1291&quot; data-start=&quot;1273&quot; data-col-size=&quot;sm&quot;&gt;더 이상 권장되지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1356&quot; data-start=&quot;1292&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1303&quot; data-start=&quot;1292&quot;&gt;SHA2(256)&lt;/td&gt;
&lt;td data-end=&quot;1316&quot; data-start=&quot;1303&quot; data-col-size=&quot;sm&quot;&gt;256&lt;/td&gt;
&lt;td data-end=&quot;1328&quot; data-start=&quot;1316&quot; data-col-size=&quot;sm&quot;&gt;64자&lt;/td&gt;
&lt;td data-end=&quot;1339&quot; data-start=&quot;1328&quot; data-col-size=&quot;sm&quot;&gt;강력&lt;/td&gt;
&lt;td data-end=&quot;1356&quot; data-start=&quot;1339&quot; data-col-size=&quot;sm&quot;&gt;가장 일반적으로 사용됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1420&quot; data-start=&quot;1357&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1368&quot; data-start=&quot;1357&quot;&gt;SHA2(512)&lt;/td&gt;
&lt;td data-end=&quot;1381&quot; data-start=&quot;1368&quot; data-col-size=&quot;sm&quot;&gt;512&lt;/td&gt;
&lt;td data-end=&quot;1393&quot; data-start=&quot;1381&quot; data-col-size=&quot;sm&quot;&gt;128자&lt;/td&gt;
&lt;td data-end=&quot;1402&quot; data-start=&quot;1393&quot; data-col-size=&quot;sm&quot;&gt;매우 강력&lt;/td&gt;
&lt;td data-end=&quot;1420&quot; data-start=&quot;1402&quot; data-col-size=&quot;sm&quot;&gt;데이터 인증/보안 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1436&quot; data-start=&quot;1422&quot; data-ke-size=&quot;size26&quot;&gt;4. 실무 활용 예제&lt;/h2&gt;
&lt;h3 data-end=&quot;1453&quot; data-start=&quot;1438&quot; data-ke-size=&quot;size23&quot;&gt;비밀번호 단방향 해싱&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408313191&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO users (username, password_hash)
VALUES ('admin', SHA2('admin1234', 256));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1614&quot; data-start=&quot;1553&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1583&quot; data-start=&quot;1553&quot;&gt;사용자가 입력한 비밀번호를 해시한 값을 DB에 저장&lt;/li&gt;
&lt;li data-end=&quot;1614&quot; data-start=&quot;1584&quot;&gt;로그인 시에도 같은 방식으로 SHA2 해시 후 비교&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1697&quot; data-start=&quot;1616&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1697&quot; data-start=&quot;1618&quot; data-ke-size=&quot;size16&quot;&gt;단, 실제 서비스에서는 MySQL보다는 &lt;b&gt;애플리케이션 레이어에서 bcrypt/argon2 등 강력한 알고리즘을 적용&lt;/b&gt;하는 것이 일반적이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;1710&quot; data-start=&quot;1699&quot; data-ke-size=&quot;size23&quot;&gt;캐시 키 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408320862&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONCAT('user_', MD5(CONCAT(user_id, '-', created_at))) AS cache_key
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1846&quot; data-start=&quot;1811&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1846&quot; data-start=&quot;1811&quot;&gt;고유 데이터를 해시로 변환하여 &lt;b&gt;중복되지 않는 키&lt;/b&gt; 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1862&quot; data-start=&quot;1848&quot; data-ke-size=&quot;size23&quot;&gt;데이터 무결성 검증&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408326911&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 원본 데이터와 해시값을 함께 저장
INSERT INTO files (filename, md5hash)
VALUES ('file.zip', MD5(file_blob));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2005&quot; data-start=&quot;1973&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2005&quot; data-start=&quot;1973&quot;&gt;추후 다운로드 후 다시 MD5 비교로 위변조 여부 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2025&quot; data-start=&quot;2007&quot; data-ke-size=&quot;size26&quot;&gt;5. 주의사항 및 권장 사용&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2318&quot; data-start=&quot;2027&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;상황&lt;/td&gt;
&lt;td&gt;권장 해시 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2173&quot; data-start=&quot;2125&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2150&quot; data-start=&quot;2125&quot;&gt;비밀번호 암호화 (권장 X)&lt;/td&gt;
&lt;td data-end=&quot;2173&quot; data-start=&quot;2150&quot; data-col-size=&quot;sm&quot;&gt;SHA2 (또는 외부 bcrypt)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2223&quot; data-start=&quot;2174&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2199&quot; data-start=&quot;2174&quot;&gt;무결성 검증 (파일, 데이터)&lt;/td&gt;
&lt;td data-end=&quot;2223&quot; data-start=&quot;2199&quot; data-col-size=&quot;sm&quot;&gt;MD5 또는 SHA1 (비보안 목적)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2265&quot; data-start=&quot;2224&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2250&quot; data-start=&quot;2224&quot;&gt;인증 토큰, 캐시 키 생성&lt;/td&gt;
&lt;td data-end=&quot;2265&quot; data-start=&quot;2250&quot; data-col-size=&quot;sm&quot;&gt;MD5 or SHA2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2318&quot; data-start=&quot;2266&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2292&quot; data-start=&quot;2266&quot;&gt;보안 민감 데이터 처리&lt;/td&gt;
&lt;td data-end=&quot;2318&quot; data-start=&quot;2292&quot; data-col-size=&quot;sm&quot;&gt;SHA2(256) 이상 또는 외부 암호화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2340&quot; data-start=&quot;2320&quot; data-ke-size=&quot;size26&quot;&gt;6. SHA2가 더 안전한 이유&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2446&quot; data-start=&quot;2342&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2365&quot; data-start=&quot;2342&quot;&gt;해시 길이가 길수록 충돌 가능성 낮아짐&lt;/li&gt;
&lt;li data-end=&quot;2394&quot; data-start=&quot;2366&quot;&gt;SHA2는 NSA 주도 하에 설계된 안전한 구조&lt;/li&gt;
&lt;li data-end=&quot;2446&quot; data-start=&quot;2395&quot;&gt;실무에서는 &lt;b&gt;SHA2(256)&lt;/b&gt; 이상을 사용해야 암호화된 데이터의 안정성이 보장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2456&quot; data-start=&quot;2448&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2618&quot; data-start=&quot;2458&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_md5&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_md5&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_sha2&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_sha2&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2701&quot; data-start=&quot;2636&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>md5</category>
      <category>MYSQL</category>
      <category>mysql보안</category>
      <category>MySQL암호화함수</category>
      <category>SHA1</category>
      <category>SHA2</category>
      <category>SQL해시함수</category>
      <category>무결성검증</category>
      <category>비밀번호암호화</category>
      <category>해시함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1087</guid>
      <comments>https://monkeybusiness.tistory.com/1087#entry1087comment</comments>
      <pubDate>Fri, 25 Jul 2025 17:49:12 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] PASSWORD와 OLD_PASSWORD 함수 완전 해부</title>
      <link>https://monkeybusiness.tistory.com/1086</link>
      <description>&lt;p data-end=&quot;340&quot; data-start=&quot;210&quot; data-ke-size=&quot;size16&quot;&gt;MySQL을 처음 접했을 때 가장 혼동하기 쉬운 것 중 하나가 바로 &lt;b&gt;PASSWORD()&lt;/b&gt; 함수다. 이 함수는 &lt;b&gt;사용자 비밀번호를 암호화하는 용도로 알려져 있지만, 실제로는 일반적인 애플리케이션에서 사용하는 해시 함수가 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;419&quot; data-start=&quot;342&quot; data-ke-size=&quot;size16&quot;&gt;또한 MySQL 버전에 따라 &lt;b&gt;OLD_PASSWORD()&lt;/b&gt;라는 함수도 함께 등장하는데, 이 둘의 차이와 사용 용도는 반드시 구분해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1f6c7/btsPxLNdy6p/ZaJc5c5yCBRkfKITRagUBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1f6c7/btsPxLNdy6p/ZaJc5c5yCBRkfKITRagUBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1f6c7/btsPxLNdy6p/ZaJc5c5yCBRkfKITRagUBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1f6c7%2FbtsPxLNdy6p%2FZaJc5c5yCBRkfKITRagUBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;524&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;439&quot; data-start=&quot;421&quot; data-ke-size=&quot;size26&quot;&gt;PASSWORD() 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408040815&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT PASSWORD('admin');
-- 결과 예시: *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;667&quot; data-start=&quot;531&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;580&quot; data-start=&quot;531&quot;&gt;MySQL 내부 사용자 인증 시스템에서 &lt;b&gt;비밀번호를 해시 저장하기 위한 함수&lt;/b&gt;다.&lt;/li&gt;
&lt;li data-end=&quot;633&quot; data-start=&quot;581&quot;&gt;SHA1과 비슷한 해시 알고리즘을 사용하며, 결과는 *로 시작하는 41자리 문자열이다.&lt;/li&gt;
&lt;li data-end=&quot;667&quot; data-start=&quot;634&quot;&gt;&lt;b&gt;애플리케이션에서 사용하도록 설계된 함수가 아니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;687&quot; data-start=&quot;669&quot; data-ke-size=&quot;size26&quot;&gt;PASSWORD 함수의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;901&quot; data-start=&quot;689&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;744&quot; data-start=&quot;689&quot;&gt;내부용도: mysql.user 테이블의 authentication_string 등에 저장&lt;/li&gt;
&lt;li data-end=&quot;831&quot; data-start=&quot;745&quot;&gt;MySQL 5.7 이후부터는 caching_sha2_password, mysql_native_password 등 &lt;b&gt;별도 인증 플러그인 사용&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;884&quot; data-start=&quot;832&quot;&gt;MySQL 8.0 이상에서는 &lt;b&gt;PASSWORD() 함수는 더 이상 기본 사용되지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;901&quot; data-start=&quot;885&quot;&gt;사용 예시는 아래와 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408050214&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 사용자 생성 시 PASSWORD() 사용 예시
CREATE USER 'test'@'localhost' IDENTIFIED WITH mysql_native_password BY 'test123';
-- 또는
SET PASSWORD FOR 'test'@'localhost' = PASSWORD('test123');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1114&quot; data-start=&quot;1092&quot; data-ke-size=&quot;size26&quot;&gt;OLD_PASSWORD() 함수란?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408055678&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT OLD_PASSWORD('admin');
-- 결과 예시: 5d2e19393cc5ef67&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1303&quot; data-start=&quot;1185&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1234&quot; data-start=&quot;1185&quot;&gt;MySQL 4.x 시절의 &lt;b&gt;구버전 해시 알고리즘&lt;/b&gt;으로 암호화된 문자열을 생성한다.&lt;/li&gt;
&lt;li data-end=&quot;1248&quot; data-start=&quot;1235&quot;&gt;16자리 문자열 반환&lt;/li&gt;
&lt;li data-end=&quot;1303&quot; data-start=&quot;1249&quot;&gt;&lt;b&gt;오래된 시스템과의 호환성 유지&lt;/b&gt;를 위해 존재하나, 보안성이 매우 낮아 실무에서 사용 금지&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1336&quot; data-start=&quot;1305&quot; data-ke-size=&quot;size26&quot;&gt;PASSWORD() vs OLD_PASSWORD()&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1569&quot; data-start=&quot;1338&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수명&lt;/td&gt;
&lt;td&gt;해시 길이&lt;/td&gt;
&lt;td&gt;보안성&lt;/td&gt;
&lt;td&gt;사용 용도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1512&quot; data-start=&quot;1456&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1473&quot; data-start=&quot;1456&quot;&gt;PASSWORD()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1485&quot; data-start=&quot;1473&quot;&gt;41자&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1492&quot; data-start=&quot;1485&quot;&gt;낮음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1512&quot; data-start=&quot;1492&quot;&gt;MySQL 내부 사용자 인증&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1569&quot; data-start=&quot;1513&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1530&quot; data-start=&quot;1513&quot;&gt;OLD_PASSWORD()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1542&quot; data-start=&quot;1530&quot;&gt;16자&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1550&quot; data-start=&quot;1542&quot;&gt;매우 낮음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1569&quot; data-start=&quot;1550&quot;&gt;구버전 호환용 (비추)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1589&quot; data-start=&quot;1571&quot; data-ke-size=&quot;size26&quot;&gt;실무에서 쓰면 안 되는 이유&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1826&quot; data-start=&quot;1591&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1669&quot; data-start=&quot;1591&quot;&gt;PASSWORD()는 MySQL의 내부 로직용 함수로, &lt;b&gt;웹 애플리케이션이나 회원 시스템에 사용하는 것은 보안상 매우 위험&lt;/b&gt;하다.&lt;/li&gt;
&lt;li data-end=&quot;1736&quot; data-start=&quot;1670&quot;&gt;보안이 강화된 SHA2(), SHA() 또는 bcrypt, argon2 등을 사용하는 것이 권장된다.&lt;/li&gt;
&lt;li data-end=&quot;1826&quot; data-start=&quot;1737&quot;&gt;비밀번호 비교 시도도 WHERE password = PASSWORD('입력값') 이런 방식은 &lt;b&gt;취약하며 SQL Injection 대응도 불완전&lt;/b&gt;하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1846&quot; data-start=&quot;1828&quot; data-ke-size=&quot;size26&quot;&gt;MySQL 권장 암호화 방식&lt;/h2&gt;
&lt;p data-end=&quot;1933&quot; data-start=&quot;1848&quot; data-ke-size=&quot;size16&quot;&gt;MySQL 8.0에서는 사용자 인증 시 mysql_native_password 대신 caching_sha2_password를 기본값으로 사용한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408086391&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE USER 'secure_user'@'%' IDENTIFIED WITH caching_sha2_password BY 'StrongP@ss!';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2079&quot; data-start=&quot;2033&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2079&quot; data-start=&quot;2033&quot;&gt;더 안전한 암호화 방식을 내부적으로 사용하며, 클라이언트 라이브러리도 호환 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2116&quot; data-start=&quot;2081&quot; data-ke-size=&quot;size26&quot;&gt;외부 애플리케이션에서 비밀번호 암호화 처리 예시 (PHP)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753408100046&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$hash = password_hash(&quot;userpassword&quot;, PASSWORD_BCRYPT);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2248&quot; data-start=&quot;2186&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2218&quot; data-start=&quot;2186&quot;&gt;MySQL에 저장할 때는 이 해시를 그대로 INSERT&lt;/li&gt;
&lt;li data-end=&quot;2248&quot; data-start=&quot;2219&quot;&gt;비교는 password_verify()로 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2255&quot; data-start=&quot;2250&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2454&quot; data-start=&quot;2257&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2343&quot; data-start=&quot;2257&quot;&gt;PASSWORD()와 OLD_PASSWORD()는 &lt;b&gt;MySQL 내부 인증을 위한 해시 함수&lt;/b&gt;로, 일반적인 애플리케이션에서 사용하면 안 된다.&lt;/li&gt;
&lt;li data-end=&quot;2400&quot; data-start=&quot;2344&quot;&gt;실무에서는 &lt;b&gt;SHA2, bcrypt, argon2 등의 강력한 암호화 방식 사용&lt;/b&gt;이 권장된다.&lt;/li&gt;
&lt;li data-end=&quot;2454&quot; data-start=&quot;2401&quot;&gt;레거시 시스템 유지보수 시 OLD_PASSWORD()와의 호환 여부만 주의해서 접근하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2464&quot; data-start=&quot;2456&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2639&quot; data-start=&quot;2466&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_password&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_password&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_old-password&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_old-password&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2745&quot; data-start=&quot;2657&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>MYSQL</category>
      <category>mysql보안</category>
      <category>MySQL암호화</category>
      <category>MySQL암호화주의사항</category>
      <category>mysql유저관리</category>
      <category>old_password</category>
      <category>PASSWORD함수</category>
      <category>사용자암호</category>
      <category>암호화함수비교</category>
      <category>해시함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1086</guid>
      <comments>https://monkeybusiness.tistory.com/1086#entry1086comment</comments>
      <pubDate>Fri, 25 Jul 2025 16:48:50 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 숫자, 날짜, 문자형 자유 변환 꿀팁 모음</title>
      <link>https://monkeybusiness.tistory.com/1085</link>
      <description>&lt;p data-end=&quot;442&quot; data-start=&quot;226&quot; data-ke-size=&quot;size16&quot;&gt;MySQL을 다루다 보면 &lt;b&gt;숫자 &amp;rarr; 문자열, 문자열 &amp;rarr; 날짜, 날짜 &amp;rarr; 숫자 등 다양한 타입 간의 변환 작업&lt;/b&gt;이 끊임없이 발생한다. 이런 변환이 실패하거나 잘못되면 쿼리 결과가 틀어지고, 성능에도 영향을 줄 수 있다. 이 글에서는 &lt;b&gt;CAST, CONVERT, STR_TO_DATE, DATE_FORMAT 등 다양한 함수들을 조합해서 실무에서 자주 사용하는 변환 패턴&lt;/b&gt;을 모아봤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBPM10/btsPx0J5R02/hp5VvXcC2CnKFmEuWtLadk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBPM10/btsPx0J5R02/hp5VvXcC2CnKFmEuWtLadk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBPM10/btsPx0J5R02/hp5VvXcC2CnKFmEuWtLadk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBPM10%2FbtsPx0J5R02%2Fhp5VvXcC2CnKFmEuWtLadk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;534&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;455&quot; data-start=&quot;444&quot; data-ke-size=&quot;size26&quot;&gt;숫자 &amp;rarr; 문자열&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407478791&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONCAT('ORD-', CAST(12345 AS CHAR)) AS 주문번호;
-- 결과: ORD-12345&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;609&quot; data-start=&quot;542&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;582&quot; data-start=&quot;542&quot;&gt;숫자를 문자열로 변환해 출력하거나 CONCAT 등에 활용할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;609&quot; data-start=&quot;583&quot;&gt;예: 휴대폰 번호, 주문번호에 접두사 붙이기&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407484247&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONCAT('ORD-', CAST(12345 AS CHAR)) AS 주문번호;
-- 결과: ORD-12345&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;703&quot; data-start=&quot;692&quot; data-ke-size=&quot;size26&quot;&gt;문자열 &amp;rarr; 숫자&lt;/h2&gt;
&lt;p data-end=&quot;763&quot; data-start=&quot;705&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 문자열이 숫자로 변환 가능한 경우 자동으로 변환되지만, 명시적으로 변환하면 더 안전하다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407490758&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST('12345' AS UNSIGNED) AS 숫자1;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;852&quot; data-start=&quot;818&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;852&quot; data-start=&quot;818&quot;&gt;문자열이 숫자가 아닐 경우 0으로 변환되므로 주의 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407496278&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST('ABC' AS SIGNED) AS 숫자;  
-- 결과: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;924&quot; data-start=&quot;913&quot; data-ke-size=&quot;size26&quot;&gt;문자열 &amp;rarr; 날짜&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407502926&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('20250723', '%Y%m%d') AS 날짜형;
-- 결과: 2025-07-23&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1087&quot; data-start=&quot;1005&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1044&quot; data-start=&quot;1005&quot;&gt;문자열 포맷이 다양할 때는 반드시 STR_TO_DATE() 사용&lt;/li&gt;
&lt;li data-end=&quot;1087&quot; data-start=&quot;1045&quot;&gt;잘못된 포맷은 NULL 반환되므로 포맷 문자열 정확히 지정해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1100&quot; data-start=&quot;1089&quot; data-ke-size=&quot;size26&quot;&gt;날짜 &amp;rarr; 문자열&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407510887&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(NOW(), '%Y/%m/%d') AS 날짜문자열;
-- 결과: 2025/07/23&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1211&quot; data-start=&quot;1180&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1211&quot; data-start=&quot;1180&quot;&gt;화면에 출력하거나, UI 전달용 API에서 자주 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1223&quot; data-start=&quot;1213&quot; data-ke-size=&quot;size26&quot;&gt;날짜 &amp;rarr; 숫자&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407517142&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT UNIX_TIMESTAMP('2025-07-23 12:00:00') AS 타임스탬프;
-- 결과: 1753220400&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1364&quot; data-start=&quot;1310&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1364&quot; data-start=&quot;1310&quot;&gt;UNIX_TIMESTAMP()는 날짜를 1970년 1월 1일 기준 초단위 정수로 바꿔준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1376&quot; data-start=&quot;1366&quot; data-ke-size=&quot;size26&quot;&gt;숫자 &amp;rarr; 날짜&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407524823&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FROM_UNIXTIME(1753220400) AS 원래날짜;
-- 결과: 2025-07-23 12:00:00&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1491&quot; data-start=&quot;1459&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1491&quot; data-start=&quot;1459&quot;&gt;저장된 타임스탬프 값을 다시 날짜형으로 복원할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1514&quot; data-start=&quot;1493&quot; data-ke-size=&quot;size26&quot;&gt;문자셋 변환 (문자열 &amp;rarr; 문자열)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407532391&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONVERT('한글문자열' USING utf8mb4);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1654&quot; data-start=&quot;1567&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1592&quot; data-start=&quot;1567&quot;&gt;문자셋 변경을 통해 인코딩 오류 해결 가능&lt;/li&gt;
&lt;li data-end=&quot;1654&quot; data-start=&quot;1593&quot;&gt;CAST는 문자셋 변경 불가 &amp;rarr; 이때는 무조건 CONVERT(str USING charset) 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1673&quot; data-start=&quot;1656&quot; data-ke-size=&quot;size26&quot;&gt;정리표: 상황별 함수 선택&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2035&quot; data-start=&quot;1675&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;변환 목적&lt;/td&gt;
&lt;td&gt;추천 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1793&quot; data-start=&quot;1754&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1770&quot; data-start=&quot;1754&quot;&gt;숫자 &amp;rarr; 문자&lt;/td&gt;
&lt;td data-end=&quot;1793&quot; data-start=&quot;1770&quot; data-col-size=&quot;sm&quot;&gt;CAST(... AS CHAR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1835&quot; data-start=&quot;1794&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1810&quot; data-start=&quot;1794&quot;&gt;문자 &amp;rarr; 숫자&lt;/td&gt;
&lt;td data-end=&quot;1835&quot; data-start=&quot;1810&quot; data-col-size=&quot;sm&quot;&gt;CAST(... AS SIGNED)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1874&quot; data-start=&quot;1836&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1851&quot; data-start=&quot;1836&quot;&gt;문자열 &amp;rarr; 날짜&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1874&quot; data-start=&quot;1851&quot;&gt;STR_TO_DATE()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1913&quot; data-start=&quot;1875&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1890&quot; data-start=&quot;1875&quot;&gt;날짜 &amp;rarr; 문자열&lt;/td&gt;
&lt;td data-end=&quot;1913&quot; data-start=&quot;1890&quot; data-col-size=&quot;sm&quot;&gt;DATE_FORMAT()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1950&quot; data-start=&quot;1914&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1927&quot; data-start=&quot;1914&quot;&gt;날짜 &amp;rarr; 타임스탬프&lt;/td&gt;
&lt;td data-end=&quot;1950&quot; data-start=&quot;1927&quot; data-col-size=&quot;sm&quot;&gt;UNIX_TIMESTAMP()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1987&quot; data-start=&quot;1951&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1964&quot; data-start=&quot;1951&quot;&gt;타임스탬프 &amp;rarr; 날짜&lt;/td&gt;
&lt;td data-end=&quot;1987&quot; data-start=&quot;1964&quot; data-col-size=&quot;sm&quot;&gt;FROM_UNIXTIME()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2035&quot; data-start=&quot;1988&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2003&quot; data-start=&quot;1988&quot;&gt;문자셋 변경&lt;/td&gt;
&lt;td data-end=&quot;2035&quot; data-start=&quot;2003&quot; data-col-size=&quot;sm&quot;&gt;CONVERT(... USING charset)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2060&quot; data-start=&quot;2037&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: JSON 필드 날짜 조합&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407551015&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  CONCAT(DATE_FORMAT(NOW(), '%Y%m%d'), '_', CAST(JSON_EXTRACT(json_data, '$.seq') AS CHAR)) AS 조합ID
FROM api_logs;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2224&quot; data-start=&quot;2197&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2224&quot; data-start=&quot;2197&quot;&gt;날짜와 숫자를 조합한 고유 식별자 생성에 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2235&quot; data-start=&quot;2226&quot; data-ke-size=&quot;size26&quot;&gt;마무리 꿀팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2374&quot; data-start=&quot;2237&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2278&quot; data-start=&quot;2237&quot;&gt;타입이 안 맞으면 암묵적 변환으로 오류나 성능 저하가 발생할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;2328&quot; data-start=&quot;2279&quot;&gt;복잡한 쿼리에서는 &lt;b&gt;명시적으로 CAST, CONVERT 등으로 타입을 지정&lt;/b&gt;하자.&lt;/li&gt;
&lt;li data-end=&quot;2374&quot; data-start=&quot;2329&quot;&gt;날짜/문자/숫자 간 변환은 모든 SQL 프로젝트에서 꼭 필요한 실전 능력이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2384&quot; data-start=&quot;2376&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2580&quot; data-start=&quot;2386&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/string-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/string-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2692&quot; data-start=&quot;2598&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>cast</category>
      <category>convert</category>
      <category>date_format</category>
      <category>from_unixtime</category>
      <category>MYSQL</category>
      <category>mysql실전팁</category>
      <category>SQL변환예제</category>
      <category>str_to_date</category>
      <category>UNIX_TIMESTAMP</category>
      <category>형변환함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1085</guid>
      <comments>https://monkeybusiness.tistory.com/1085#entry1085comment</comments>
      <pubDate>Fri, 25 Jul 2025 15:39:58 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 날짜 &amp;rarr; 문자열 변환: DATE_FORMAT 응용하기  ️</title>
      <link>https://monkeybusiness.tistory.com/1084</link>
      <description>&lt;p data-end=&quot;353&quot; data-start=&quot;229&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 날짜를 가독성 좋은 문자열로 출력해야 하는 경우가 많다. 보고용, 프론트 전달용, 로그 출력용, 또는 사용자에게 보여주는 UI 처리 등 &lt;b&gt;날짜를 다양한 포맷의 문자열로 바꾸는 작업은 실무에서 필수적&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;434&quot; data-start=&quot;355&quot; data-ke-size=&quot;size16&quot;&gt;이럴 때 사용하는 함수가 바로 &lt;b&gt;DATE_FORMAT()&lt;/b&gt; 함수다. 이 함수는 날짜를 원하는 형식의 문자열로 자유롭게 변환할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZDily/btsPzgya6DG/xh4pwKQfZGXdNsRlPtEuV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZDily/btsPzgya6DG/xh4pwKQfZGXdNsRlPtEuV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZDily/btsPzgya6DG/xh4pwKQfZGXdNsRlPtEuV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZDily%2FbtsPzgya6DG%2Fxh4pwKQfZGXdNsRlPtEuV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;524&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;453&quot; data-start=&quot;436&quot; data-ke-size=&quot;size26&quot;&gt;DATE_FORMAT 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407257991&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DATE_FORMAT(날짜값, '포맷문자열')&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;569&quot; data-start=&quot;493&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;537&quot; data-start=&quot;493&quot;&gt;첫 번째 인자: DATE, DATETIME, TIMESTAMP 값&lt;/li&gt;
&lt;li data-end=&quot;569&quot; data-start=&quot;538&quot;&gt;두 번째 인자: 출력할 문자열 형식(포맷 코드 조합)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;587&quot; data-start=&quot;571&quot; data-ke-size=&quot;size26&quot;&gt;자주 사용하는 포맷 코드&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1127&quot; data-start=&quot;589&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;코드&lt;/td&gt;
&lt;td&gt;의미&lt;/td&gt;
&lt;td&gt;예시 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;692&quot; data-start=&quot;658&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;665&quot; data-start=&quot;658&quot;&gt;%Y&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;677&quot; data-start=&quot;665&quot;&gt;4자리 연도&lt;/td&gt;
&lt;td data-end=&quot;692&quot; data-start=&quot;677&quot; data-col-size=&quot;sm&quot;&gt;2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;727&quot; data-start=&quot;693&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;700&quot; data-start=&quot;693&quot;&gt;%y&lt;/td&gt;
&lt;td data-end=&quot;712&quot; data-start=&quot;700&quot; data-col-size=&quot;sm&quot;&gt;2자리 연도&lt;/td&gt;
&lt;td data-end=&quot;727&quot; data-start=&quot;712&quot; data-col-size=&quot;sm&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;763&quot; data-start=&quot;728&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;735&quot; data-start=&quot;728&quot;&gt;%m&lt;/td&gt;
&lt;td data-end=&quot;748&quot; data-start=&quot;735&quot; data-col-size=&quot;sm&quot;&gt;2자리 월&lt;/td&gt;
&lt;td data-end=&quot;763&quot; data-start=&quot;748&quot; data-col-size=&quot;sm&quot;&gt;07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;799&quot; data-start=&quot;764&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;771&quot; data-start=&quot;764&quot;&gt;%c&lt;/td&gt;
&lt;td data-end=&quot;784&quot; data-start=&quot;771&quot; data-col-size=&quot;sm&quot;&gt;월(숫자, 1~12)&lt;/td&gt;
&lt;td data-end=&quot;799&quot; data-start=&quot;784&quot; data-col-size=&quot;sm&quot;&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;835&quot; data-start=&quot;800&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;807&quot; data-start=&quot;800&quot;&gt;%d&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;820&quot; data-start=&quot;807&quot;&gt;2자리 일&lt;/td&gt;
&lt;td data-end=&quot;835&quot; data-start=&quot;820&quot; data-col-size=&quot;sm&quot;&gt;09&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;871&quot; data-start=&quot;836&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;843&quot; data-start=&quot;836&quot;&gt;%e&lt;/td&gt;
&lt;td data-end=&quot;856&quot; data-start=&quot;843&quot; data-col-size=&quot;sm&quot;&gt;일(숫자, 1~31)&lt;/td&gt;
&lt;td data-end=&quot;871&quot; data-start=&quot;856&quot; data-col-size=&quot;sm&quot;&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;909&quot; data-start=&quot;872&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;879&quot; data-start=&quot;872&quot;&gt;%H&lt;/td&gt;
&lt;td data-end=&quot;894&quot; data-start=&quot;879&quot; data-col-size=&quot;sm&quot;&gt;시(00~23)&lt;/td&gt;
&lt;td data-end=&quot;909&quot; data-start=&quot;894&quot; data-col-size=&quot;sm&quot;&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;947&quot; data-start=&quot;910&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;917&quot; data-start=&quot;910&quot;&gt;%i&lt;/td&gt;
&lt;td data-end=&quot;932&quot; data-start=&quot;917&quot; data-col-size=&quot;sm&quot;&gt;분&lt;/td&gt;
&lt;td data-end=&quot;947&quot; data-start=&quot;932&quot; data-col-size=&quot;sm&quot;&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;985&quot; data-start=&quot;948&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;955&quot; data-start=&quot;948&quot;&gt;%s&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;970&quot; data-start=&quot;955&quot;&gt;초&lt;/td&gt;
&lt;td data-end=&quot;985&quot; data-start=&quot;970&quot; data-col-size=&quot;sm&quot;&gt;59&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1021&quot; data-start=&quot;986&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;993&quot; data-start=&quot;986&quot;&gt;%W&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1006&quot; data-start=&quot;993&quot;&gt;요일 이름&lt;/td&gt;
&lt;td data-end=&quot;1021&quot; data-start=&quot;1006&quot; data-col-size=&quot;sm&quot;&gt;Wednesday&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1057&quot; data-start=&quot;1022&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1029&quot; data-start=&quot;1022&quot;&gt;%a&lt;/td&gt;
&lt;td data-end=&quot;1042&quot; data-start=&quot;1029&quot; data-col-size=&quot;sm&quot;&gt;요일 약자&lt;/td&gt;
&lt;td data-end=&quot;1057&quot; data-start=&quot;1042&quot; data-col-size=&quot;sm&quot;&gt;Wed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1092&quot; data-start=&quot;1058&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1065&quot; data-start=&quot;1058&quot;&gt;%b&lt;/td&gt;
&lt;td data-end=&quot;1077&quot; data-start=&quot;1065&quot; data-col-size=&quot;sm&quot;&gt;월 이름 약자&lt;/td&gt;
&lt;td data-end=&quot;1092&quot; data-start=&quot;1077&quot; data-col-size=&quot;sm&quot;&gt;Jul&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1127&quot; data-start=&quot;1093&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1100&quot; data-start=&quot;1093&quot;&gt;%M&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1112&quot; data-start=&quot;1100&quot;&gt;월 전체 이름&lt;/td&gt;
&lt;td data-end=&quot;1127&quot; data-start=&quot;1112&quot; data-col-size=&quot;sm&quot;&gt;July&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1159&quot; data-start=&quot;1129&quot; data-ke-size=&quot;size26&quot;&gt;예제 1: 날짜를 YYYY-MM-DD 형식으로&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407281071&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(NOW(), '%Y-%m-%d') AS 오늘날짜;
-- 결과: 2025-07-23&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1262&quot; data-start=&quot;1238&quot; data-ke-size=&quot;size26&quot;&gt;예제 2: 날짜 + 시간 문자열로 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407286191&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS 전체포맷;
-- 결과: 2025-07-23 15:47:21&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1382&quot; data-start=&quot;1359&quot; data-ke-size=&quot;size26&quot;&gt;예제 3: 한국식 날짜 포맷으로 출력&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407292024&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(NOW(), '%Y년 %m월 %d일') AS 한국형날짜;
-- 결과: 2025년 07월 23일&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1488&quot; data-start=&quot;1468&quot; data-ke-size=&quot;size26&quot;&gt;예제 4: 요일 이름 포함 포맷&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407299831&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT('2025-07-23', '%Y-%m-%d (%W)') AS 요일포함;
-- 결과: 2025-07-23 (Wednesday)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1617&quot; data-start=&quot;1591&quot; data-ke-size=&quot;size26&quot;&gt;예제 5: 블로그/게시판 날짜 포맷 만들기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407305783&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(NOW(), '%y.%m.%d %H:%i') AS 게시판용;
-- 결과: 25.07.23 15:47&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1716&quot; data-start=&quot;1706&quot; data-ke-size=&quot;size26&quot;&gt;실무 활용 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1887&quot; data-start=&quot;1718&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1784&quot; data-start=&quot;1718&quot;&gt;&lt;b&gt;UI/프론트 전달용 날짜 포맷&lt;/b&gt;은 DATE_FORMAT()으로 가공 후 전달하면 프론트 처리 부담 감소&lt;/li&gt;
&lt;li data-end=&quot;1842&quot; data-start=&quot;1785&quot;&gt;&lt;b&gt;로그 포맷&lt;/b&gt;이나 &lt;b&gt;데이터 내보내기(EXPORT)&lt;/b&gt; 시 CSV 내 날짜 문자열 출력 가능&lt;/li&gt;
&lt;li data-end=&quot;1887&quot; data-start=&quot;1843&quot;&gt;%Y-%m 같은 월 단위 포맷으로 &lt;b&gt;월별 통계 키 생성&lt;/b&gt;에 활용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407314918&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(order_date, '%Y-%m') AS 월별,
       COUNT(*) AS 주문수
FROM orders
GROUP BY 월별;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2014&quot; data-start=&quot;1996&quot; data-ke-size=&quot;size26&quot;&gt;STR_TO_DATE와 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2150&quot; data-start=&quot;2016&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;함수명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2117&quot; data-start=&quot;2085&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2098&quot; data-start=&quot;2085&quot;&gt;문자열 &amp;rarr; 날짜&lt;/td&gt;
&lt;td data-end=&quot;2117&quot; data-start=&quot;2098&quot; data-col-size=&quot;sm&quot;&gt;STR_TO_DATE()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2150&quot; data-start=&quot;2118&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2131&quot; data-start=&quot;2118&quot;&gt;날짜 &amp;rarr; 문자열&lt;/td&gt;
&lt;td data-end=&quot;2150&quot; data-start=&quot;2131&quot; data-col-size=&quot;sm&quot;&gt;DATE_FORMAT()&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2191&quot; data-start=&quot;2152&quot; data-ke-size=&quot;size16&quot;&gt;이 둘은 &lt;b&gt;쌍을 이루는 반대 동작의 함수&lt;/b&gt;로, 함께 자주 사용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;2198&quot; data-start=&quot;2193&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2347&quot; data-start=&quot;2200&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2254&quot; data-start=&quot;2200&quot;&gt;DATE_FORMAT()은 날짜를 원하는 형태의 문자열로 가공하는 데 특화된 함수이다.&lt;/li&gt;
&lt;li data-end=&quot;2305&quot; data-start=&quot;2255&quot;&gt;다양한 포맷 코드 조합으로 한국식, 미국식, 시간 포함 등 자유롭게 표현 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;2347&quot; data-start=&quot;2306&quot;&gt;실무에서 UI, 로그, 통계, 리포트 등 다양한 곳에 폭넓게 활용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2357&quot; data-start=&quot;2349&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2448&quot; data-start=&quot;2359&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2549&quot; data-start=&quot;2466&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>date_format</category>
      <category>MYSQL</category>
      <category>MySQL날짜가공</category>
      <category>MySQL날짜표현</category>
      <category>mysql실무예제</category>
      <category>SQL날짜함수</category>
      <category>UI날짜출력</category>
      <category>날짜문자열변환</category>
      <category>날짜포맷</category>
      <category>한국형날짜포맷</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1084</guid>
      <comments>https://monkeybusiness.tistory.com/1084#entry1084comment</comments>
      <pubDate>Fri, 25 Jul 2025 14:35:54 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 문자열 &amp;rarr; 날짜 변환: STR_TO_DATE 실전 예제  </title>
      <link>https://monkeybusiness.tistory.com/1083</link>
      <description>&lt;p data-end=&quot;372&quot; data-start=&quot;211&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 날짜 데이터를 처리할 때 가장 자주 마주치는 이슈 중 하나는 &lt;b&gt;문자열로 저장된 날짜를 DATE 타입으로 변환하는 문제&lt;/b&gt;다. 예를 들어 '2025-07-23', '20250723', '07/23/2025'처럼 포맷이 다양한 문자열을 날짜로 바꿔야 할 때가 많다.&lt;/p&gt;
&lt;p data-end=&quot;481&quot; data-start=&quot;374&quot; data-ke-size=&quot;size16&quot;&gt;이럴 때 사용하는 함수가 바로 &lt;b&gt;STR_TO_DATE()&lt;/b&gt;다. &lt;b&gt;STR_TO_DATE는 문자열을 지정한 날짜 포맷으로 해석하여 DATE, DATETIME 등의 형식으로 변환&lt;/b&gt;해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ASwbF/btsPybq28vP/4j6KYe54hdBSucMBvupxVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ASwbF/btsPybq28vP/4j6KYe54hdBSucMBvupxVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ASwbF/btsPybq28vP/4j6KYe54hdBSucMBvupxVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FASwbF%2FbtsPybq28vP%2F4j6KYe54hdBSucMBvupxVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;524&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;500&quot; data-start=&quot;483&quot; data-ke-size=&quot;size26&quot;&gt;STR_TO_DATE 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407110062&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;STR_TO_DATE(문자열, 포맷문자열)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;591&quot; data-start=&quot;538&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;560&quot; data-start=&quot;538&quot;&gt;첫 번째 인자: 날짜로 변환할 문자열&lt;/li&gt;
&lt;li data-end=&quot;591&quot; data-start=&quot;561&quot;&gt;두 번째 인자: 문자열의 포맷을 나타내는 포맷 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;609&quot; data-start=&quot;593&quot; data-ke-size=&quot;size26&quot;&gt;자주 사용하는 포맷 코드&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1018&quot; data-start=&quot;611&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;코드&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;td&gt;예시 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;717&quot; data-start=&quot;682&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;689&quot; data-start=&quot;682&quot;&gt;%Y&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;702&quot; data-start=&quot;689&quot;&gt;4자리 연도&lt;/td&gt;
&lt;td data-end=&quot;717&quot; data-start=&quot;702&quot; data-col-size=&quot;sm&quot;&gt;2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;753&quot; data-start=&quot;718&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;725&quot; data-start=&quot;718&quot;&gt;%y&lt;/td&gt;
&lt;td data-end=&quot;738&quot; data-start=&quot;725&quot; data-col-size=&quot;sm&quot;&gt;2자리 연도&lt;/td&gt;
&lt;td data-end=&quot;753&quot; data-start=&quot;738&quot; data-col-size=&quot;sm&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;792&quot; data-start=&quot;754&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;761&quot; data-start=&quot;754&quot;&gt;%m&lt;/td&gt;
&lt;td data-end=&quot;777&quot; data-start=&quot;761&quot; data-col-size=&quot;sm&quot;&gt;월 (01~12)&lt;/td&gt;
&lt;td data-end=&quot;792&quot; data-start=&quot;777&quot; data-col-size=&quot;sm&quot;&gt;07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;831&quot; data-start=&quot;793&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;800&quot; data-start=&quot;793&quot;&gt;%d&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;816&quot; data-start=&quot;800&quot;&gt;일 (01~31)&lt;/td&gt;
&lt;td data-end=&quot;831&quot; data-start=&quot;816&quot; data-col-size=&quot;sm&quot;&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;870&quot; data-start=&quot;832&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;839&quot; data-start=&quot;832&quot;&gt;%H&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;855&quot; data-start=&quot;839&quot;&gt;시 (00~23)&lt;/td&gt;
&lt;td data-end=&quot;870&quot; data-start=&quot;855&quot; data-col-size=&quot;sm&quot;&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;909&quot; data-start=&quot;871&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;878&quot; data-start=&quot;871&quot;&gt;%i&lt;/td&gt;
&lt;td data-end=&quot;894&quot; data-start=&quot;878&quot; data-col-size=&quot;sm&quot;&gt;분 (00~59)&lt;/td&gt;
&lt;td data-end=&quot;909&quot; data-start=&quot;894&quot; data-col-size=&quot;sm&quot;&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;948&quot; data-start=&quot;910&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;917&quot; data-start=&quot;910&quot;&gt;%s&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;933&quot; data-start=&quot;917&quot;&gt;초 (00~59)&lt;/td&gt;
&lt;td data-end=&quot;948&quot; data-start=&quot;933&quot; data-col-size=&quot;sm&quot;&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;983&quot; data-start=&quot;949&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;956&quot; data-start=&quot;949&quot;&gt;%b&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;968&quot; data-start=&quot;956&quot;&gt;약식 월 이름&lt;/td&gt;
&lt;td data-end=&quot;983&quot; data-start=&quot;968&quot; data-col-size=&quot;sm&quot;&gt;Jul&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1018&quot; data-start=&quot;984&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;991&quot; data-start=&quot;984&quot;&gt;%M&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1003&quot; data-start=&quot;991&quot;&gt;전체 월 이름&lt;/td&gt;
&lt;td data-end=&quot;1018&quot; data-start=&quot;1003&quot; data-col-size=&quot;sm&quot;&gt;July&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1043&quot; data-start=&quot;1020&quot; data-ke-size=&quot;size16&quot;&gt;자세한 포맷은 공식 문서를 참고하면 된다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1073&quot; data-start=&quot;1045&quot; data-ke-size=&quot;size26&quot;&gt;예제 1: '20250723' &amp;rarr; 날짜로 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407132510&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('20250723', '%Y%m%d') AS 변환날짜;
-- 결과: 2025-07-23&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1185&quot; data-start=&quot;1155&quot; data-ke-size=&quot;size26&quot;&gt;예제 2: '07/23/2025' &amp;rarr; 날짜로 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407138415&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('07/23/2025', '%m/%d/%Y') AS 변환날짜;
-- 결과: 2025-07-23&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1295&quot; data-start=&quot;1271&quot; data-ke-size=&quot;size26&quot;&gt;예제 3: 시간까지 포함된 문자열 처리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407143951&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('2025-07-23 14:35:27', '%Y-%m-%d %H:%i:%s') AS 날짜시간;
-- 결과: 2025-07-23 14:35:27&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1430&quot; data-start=&quot;1408&quot; data-ke-size=&quot;size26&quot;&gt;예제 4: 월 이름으로 표현된 날짜&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407159007&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('Jul 23, 2025', '%b %d, %Y') AS 날짜;
-- 결과: 2025-07-23&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1542&quot; data-start=&quot;1517&quot; data-ke-size=&quot;size26&quot;&gt;예제 5: 잘못된 포맷 &amp;rarr; NULL 반환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407164311&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('23-07-2025', '%Y/%m/%d') AS 실패예시;
-- 결과: NULL&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1680&quot; data-start=&quot;1622&quot; data-ke-size=&quot;size16&quot;&gt;날짜 문자열과 포맷이 일치하지 않으면 NULL이 반환되므로 &lt;b&gt;항상 포맷을 정확히 지정&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1689&quot; data-start=&quot;1682&quot; data-ke-size=&quot;size26&quot;&gt;실무 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1799&quot; data-start=&quot;1691&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1743&quot; data-start=&quot;1691&quot;&gt;다양한 시스템에서 가져온 CSV 데이터, 로그 파일, 사용자 입력 등을 처리할 때 필수&lt;/li&gt;
&lt;li data-end=&quot;1774&quot; data-start=&quot;1744&quot;&gt;쿼리에서 직접 변환하거나, ETL 처리 시 사용&lt;/li&gt;
&lt;li data-end=&quot;1799&quot; data-start=&quot;1775&quot;&gt;날짜로 변환 후 정렬, 비교, 연산 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407170918&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM access_log
WHERE STR_TO_DATE(log_time_str, '%Y%m%d%H%i%S') BETWEEN '2025-07-01' AND '2025-07-31';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1938&quot; data-start=&quot;1925&quot; data-ke-size=&quot;size26&quot;&gt;CAST와의 차이점&lt;/h2&gt;
&lt;p data-end=&quot;2058&quot; data-start=&quot;1940&quot; data-ke-size=&quot;size16&quot;&gt;CAST()는 '2025-07-23'처럼 &lt;b&gt;MySQL이 인식 가능한 표준 날짜 포맷&lt;/b&gt;만 변환할 수 있다.&lt;br /&gt;&lt;b&gt;STR_TO_DATE는 비표준 포맷도 명시적으로 변환 가능&lt;/b&gt;하기 때문에 훨씬 유연하다.&lt;/p&gt;
&lt;h2 data-end=&quot;2065&quot; data-start=&quot;2060&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2216&quot; data-start=&quot;2067&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2125&quot; data-start=&quot;2067&quot;&gt;STR_TO_DATE()는 &lt;b&gt;비표준 문자열을 날짜 타입으로 바꾸는 가장 강력한 방법&lt;/b&gt;이다.&lt;/li&gt;
&lt;li data-end=&quot;2171&quot; data-start=&quot;2126&quot;&gt;포맷 코드를 정확히 지정해야 하며, 잘못 지정하면 NULL이 반환된다.&lt;/li&gt;
&lt;li data-end=&quot;2216&quot; data-start=&quot;2172&quot;&gt;실무에서 CSV, Excel, 사용자 입력 데이터 처리 시 필수로 활용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2226&quot; data-start=&quot;2218&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2317&quot; data-start=&quot;2228&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_str-to-date&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_str-to-date&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2419&quot; data-start=&quot;2335&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>CSV날짜처리</category>
      <category>MYSQL</category>
      <category>mysql날짜함수</category>
      <category>mysql실무팁</category>
      <category>mysql쿼리예제</category>
      <category>SQL포맷변환</category>
      <category>str_to_date</category>
      <category>날짜형변환</category>
      <category>문자열날짜변환</category>
      <category>비표준날짜처리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1083</guid>
      <comments>https://monkeybusiness.tistory.com/1083#entry1083comment</comments>
      <pubDate>Fri, 25 Jul 2025 13:33:33 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] CONVERT 함수와 CAST 차이점 비교</title>
      <link>https://monkeybusiness.tistory.com/1082</link>
      <description>&lt;p data-end=&quot;392&quot; data-start=&quot;199&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 데이터 타입을 변환하는 대표적인 함수는 &lt;b&gt;CAST()와 CONVERT()&lt;/b&gt;이다. 이 두 함수는 기본적으로 동일한 기능을 제공하지만, &lt;b&gt;문법과 확장 기능에 차이가 있다&lt;/b&gt;. 특히 CONVERT()는 문자셋 변경에도 사용되기 때문에 &lt;b&gt;두 함수의 차이점을 명확히 이해하고 상황에 맞게 선택하는 것이 중요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WPuOP/btsPxl85fl0/ik4ZKm6alvkbctJFJQbjOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WPuOP/btsPxl85fl0/ik4ZKm6alvkbctJFJQbjOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WPuOP/btsPxl85fl0/ik4ZKm6alvkbctJFJQbjOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWPuOP%2FbtsPxl85fl0%2Fik4ZKm6alvkbctJFJQbjOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;536&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;409&quot; data-start=&quot;394&quot; data-ke-size=&quot;size26&quot;&gt;공통점: 형 변환 함수&lt;/h2&gt;
&lt;p data-end=&quot;468&quot; data-start=&quot;411&quot; data-ke-size=&quot;size16&quot;&gt;둘 다 SQL 표준에 기반한 &lt;b&gt;형 변환 함수&lt;/b&gt;로, 다양한 데이터 타입 간의 명시적 변환을 수행한다.&lt;/p&gt;
&lt;h2 data-end=&quot;483&quot; data-start=&quot;470&quot; data-ke-size=&quot;size26&quot;&gt;CAST 함수 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406965311&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CAST(값 AS 데이터타입)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;516&quot; data-start=&quot;514&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406970582&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST(123.45 AS CHAR) AS 문자;
-- 결과: '123.45'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;597&quot; data-start=&quot;581&quot; data-ke-size=&quot;size26&quot;&gt;CONVERT 함수 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406975150&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CONVERT(값, 데이터타입)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;631&quot; data-start=&quot;629&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406980655&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONVERT(123.45, CHAR) AS 문자;
-- 결과: '123.45'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;721&quot; data-start=&quot;697&quot; data-ke-size=&quot;size16&quot;&gt;문법만 다를 뿐, 기본적인 동작은 동일하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;735&quot; data-start=&quot;723&quot; data-ke-size=&quot;size26&quot;&gt;주요 차이점 정리&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;968&quot; data-start=&quot;737&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;CAST&lt;/td&gt;
&lt;td&gt;CONVERT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;805&quot; data-start=&quot;787&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;796&quot; data-start=&quot;787&quot;&gt;SQL 표준&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;800&quot; data-start=&quot;796&quot;&gt;O&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;805&quot; data-start=&quot;800&quot;&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;859&quot; data-start=&quot;806&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;811&quot; data-start=&quot;806&quot;&gt;문법&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;834&quot; data-start=&quot;811&quot;&gt;CAST(expr AS type)&lt;/td&gt;
&lt;td data-end=&quot;859&quot; data-start=&quot;834&quot; data-col-size=&quot;sm&quot;&gt;CONVERT(expr, type)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;912&quot; data-start=&quot;860&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;869&quot; data-start=&quot;860&quot;&gt;문자셋 변경&lt;/td&gt;
&lt;td data-end=&quot;875&quot; data-start=&quot;869&quot; data-col-size=&quot;sm&quot;&gt;불가능&lt;/td&gt;
&lt;td data-end=&quot;912&quot; data-start=&quot;875&quot; data-col-size=&quot;sm&quot;&gt;가능 (CONVERT(str USING charset))&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;937&quot; data-start=&quot;913&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;919&quot; data-start=&quot;913&quot;&gt;가독성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;926&quot; data-start=&quot;919&quot;&gt;더 명확&lt;/td&gt;
&lt;td data-end=&quot;937&quot; data-start=&quot;926&quot; data-col-size=&quot;sm&quot;&gt;함수형 스타일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;968&quot; data-start=&quot;938&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;944&quot; data-start=&quot;938&quot;&gt;확장성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;953&quot; data-start=&quot;944&quot;&gt;고정된 용도&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;968&quot; data-start=&quot;953&quot;&gt;문자셋 변환까지 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;984&quot; data-start=&quot;970&quot; data-ke-size=&quot;size26&quot;&gt;예제 1: 같은 결과&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407006478&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST(1234 AS CHAR) AS cast_result,
       CONVERT(1234, CHAR) AS convert_result;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1110&quot; data-start=&quot;1086&quot; data-ke-size=&quot;size16&quot;&gt;결과는 동일하게 '1234'로 출력된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1140&quot; data-start=&quot;1112&quot; data-ke-size=&quot;size26&quot;&gt;예제 2: 문자셋 변환 (CONVERT 전용)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407013303&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONVERT('안녕하세요' USING utf8mb4);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1266&quot; data-start=&quot;1193&quot; data-ke-size=&quot;size16&quot;&gt;이건 CAST()로는 할 수 없다. CONVERT()는 문자열의 인코딩을 명시적으로 지정할 수 있어 문자셋 처리에 강력하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1285&quot; data-start=&quot;1268&quot; data-ke-size=&quot;size26&quot;&gt;예제 3: 날짜 포맷 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753407018896&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  CAST('2025-07-22' AS DATE) AS cast_date,
  CONVERT('2025-07-22', DATE) AS convert_date;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1419&quot; data-start=&quot;1397&quot; data-ke-size=&quot;size16&quot;&gt;둘 다 결과는 동일하게 날짜로 변환된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1444&quot; data-start=&quot;1421&quot; data-ke-size=&quot;size26&quot;&gt;언제 CAST? 언제 CONVERT?&lt;/h2&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1446&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;문자셋 변환이 필요한 경우&lt;/b&gt; &amp;rarr; CONVERT(str USING charset)&lt;br /&gt;✅ &lt;b&gt;SQL 표준 스타일이 필요한 경우&lt;/b&gt; &amp;rarr; CAST()&lt;br /&gt;✅ &lt;b&gt;직관적인 함수 스타일을 선호한다면&lt;/b&gt; &amp;rarr; CONVERT()&lt;/p&gt;
&lt;p data-end=&quot;1649&quot; data-start=&quot;1580&quot; data-ke-size=&quot;size16&quot;&gt;실제로 성능이나 결과 차이는 거의 없기 때문에, &lt;b&gt;문법 스타일과 가독성, 특수 기능(문자셋)을 기준으로 선택&lt;/b&gt;하면 된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1656&quot; data-start=&quot;1651&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1849&quot; data-start=&quot;1658&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1708&quot; data-start=&quot;1658&quot;&gt;CAST()와 CONVERT()는 대부분의 형 변환에서 동일한 역할을 한다.&lt;/li&gt;
&lt;li data-end=&quot;1744&quot; data-start=&quot;1709&quot;&gt;문법은 다르지만 결과는 거의 같으며, 성능 차이도 없다.&lt;/li&gt;
&lt;li data-end=&quot;1788&quot; data-start=&quot;1745&quot;&gt;CONVERT()는 &lt;b&gt;문자셋 변환&lt;/b&gt;이 가능한 유일한 선택지이다.&lt;/li&gt;
&lt;li data-end=&quot;1849&quot; data-start=&quot;1789&quot;&gt;실무에서는 문자셋 처리, 데이터 포맷 일관성 확보를 위해 &lt;b&gt;상황별로 적절히 선택하는 것이 중요하다&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1859&quot; data-start=&quot;1851&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;1983&quot; data-start=&quot;1861&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/charset-convert.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/charset-convert.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2080&quot; data-start=&quot;2001&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>cast</category>
      <category>convert</category>
      <category>CONVERT사용법</category>
      <category>MYSQL</category>
      <category>MySQLCONVERT</category>
      <category>MySQL문자열처리</category>
      <category>SQL형변환</category>
      <category>문자셋변환</category>
      <category>타입변환비교</category>
      <category>형변환함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1082</guid>
      <comments>https://monkeybusiness.tistory.com/1082#entry1082comment</comments>
      <pubDate>Fri, 25 Jul 2025 12:30:38 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] CAST 함수로 데이터 형 변환하기</title>
      <link>https://monkeybusiness.tistory.com/1081</link>
      <description>&lt;p data-end=&quot;330&quot; data-start=&quot;196&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 데이터를 다루다 보면 문자열을 숫자로, 날짜를 문자열로, 혹은 정수를 실수로 &lt;b&gt;형 변환(type conversion)&lt;/b&gt; 해야 하는 상황이 자주 발생한다. 이때 사용하는 대표적인 함수가 바로 &lt;b&gt;CAST()&lt;/b&gt; 함수이다.&lt;/p&gt;
&lt;p data-end=&quot;433&quot; data-start=&quot;332&quot; data-ke-size=&quot;size16&quot;&gt;CAST()는 SQL 표준에 따른 &lt;b&gt;명시적 형 변환(explicit conversion)&lt;/b&gt; 함수로, 데이터 타입을 명확히 지정해 안전하고 예측 가능한 변환을 수행할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRxS2d/btsPyYLeH2x/D11rcdPII2ghgUpk7Fcfs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRxS2d/btsPyYLeH2x/D11rcdPII2ghgUpk7Fcfs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRxS2d/btsPyYLeH2x/D11rcdPII2ghgUpk7Fcfs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRxS2d%2FbtsPyYLeH2x%2FD11rcdPII2ghgUpk7Fcfs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;573&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;448&quot; data-start=&quot;435&quot; data-ke-size=&quot;size26&quot;&gt;CAST 함수 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406791775&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CAST(값 AS 데이터타입)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;549&quot; data-start=&quot;479&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;492&quot; data-start=&quot;479&quot;&gt;값: 변환할 대상&lt;/li&gt;
&lt;li data-end=&quot;549&quot; data-start=&quot;493&quot;&gt;데이터타입: 변환할 목표 타입 (예: CHAR, DATE, SIGNED, UNSIGNED 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;568&quot; data-start=&quot;551&quot; data-ke-size=&quot;size26&quot;&gt;지원하는 주요 데이터 타입&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;995&quot; data-start=&quot;570&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;타입 이름&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;714&quot; data-start=&quot;666&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;683&quot; data-start=&quot;666&quot;&gt;CHAR&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;714&quot; data-start=&quot;683&quot;&gt;문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;764&quot; data-start=&quot;715&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;732&quot; data-start=&quot;715&quot;&gt;DATE&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;764&quot; data-start=&quot;732&quot;&gt;날짜&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;811&quot; data-start=&quot;765&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;782&quot; data-start=&quot;765&quot;&gt;DATETIME&lt;/td&gt;
&lt;td data-end=&quot;811&quot; data-start=&quot;782&quot; data-col-size=&quot;sm&quot;&gt;날짜 및 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;857&quot; data-start=&quot;812&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;829&quot; data-start=&quot;812&quot;&gt;SIGNED&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;857&quot; data-start=&quot;829&quot;&gt;부호 있는 정수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;903&quot; data-start=&quot;858&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;875&quot; data-start=&quot;858&quot;&gt;UNSIGNED&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;903&quot; data-start=&quot;875&quot;&gt;부호 없는 정수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;948&quot; data-start=&quot;904&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;921&quot; data-start=&quot;904&quot;&gt;DECIMAL(M,D)&lt;/td&gt;
&lt;td data-end=&quot;948&quot; data-start=&quot;921&quot; data-col-size=&quot;sm&quot;&gt;고정 소수점 숫자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;995&quot; data-start=&quot;949&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;966&quot; data-start=&quot;949&quot;&gt;BINARY&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;995&quot; data-start=&quot;966&quot;&gt;이진 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1018&quot; data-start=&quot;997&quot; data-ke-size=&quot;size26&quot;&gt;예제 1: 숫자 &amp;rarr; 문자열로 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406818976&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST(12345 AS CHAR) AS 문자열변환;
-- 결과: '12345'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1126&quot; data-start=&quot;1084&quot; data-ke-size=&quot;size16&quot;&gt;숫자를 문자형으로 변환하면 문자열 처리 함수나 LIKE 검색 등에 유용하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1148&quot; data-start=&quot;1128&quot; data-ke-size=&quot;size26&quot;&gt;예제 2: 문자열 &amp;rarr; 숫자 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406824374&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST('3.14' AS DECIMAL(5,2)) AS 실수변환;
-- 결과: 3.14&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1264&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;문자열 숫자를 DECIMAL 또는 SIGNED로 변환하면 계산에 활용할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1286&quot; data-start=&quot;1266&quot; data-ke-size=&quot;size26&quot;&gt;예제 3: 문자열 &amp;rarr; 날짜 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406833270&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST('2025-07-22' AS DATE) AS 날짜;
-- 결과: 2025-07-22&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1436&quot; data-start=&quot;1359&quot; data-ke-size=&quot;size16&quot;&gt;단, 날짜 형식이 MySQL의 날짜 포맷과 다르면 변환 실패할 수 있으므로 STR_TO_DATE()를 쓰는 게 더 안전한 경우도 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1460&quot; data-start=&quot;1438&quot; data-ke-size=&quot;size26&quot;&gt;예제 4: 정수 &amp;rarr; 부호 없는 정수&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406839455&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST(-123 AS UNSIGNED) AS 음수제거;
-- 결과: 18446744073709551593 (오버플로우 처리됨)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1605&quot; data-start=&quot;1553&quot; data-ke-size=&quot;size16&quot;&gt;SIGNED &amp;harr; UNSIGNED 변환 시에는 &lt;b&gt;범위 제한이나 오버플로우 주의&lt;/b&gt;가 필요하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1634&quot; data-start=&quot;1607&quot; data-ke-size=&quot;size26&quot;&gt;예제 5: 실무 활용 - 형변환과 연산 조합&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753406847598&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT price, quantity,
       price * CAST(quantity AS UNSIGNED) AS 총합
FROM orders;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1781&quot; data-start=&quot;1733&quot; data-ke-size=&quot;size16&quot;&gt;숫자가 문자열로 저장되어 있는 경우 연산 전 형 변환을 해주면 정확한 계산이 가능하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1800&quot; data-start=&quot;1783&quot; data-ke-size=&quot;size26&quot;&gt;CAST vs 암시적 변환&lt;/h2&gt;
&lt;p data-end=&quot;1914&quot; data-start=&quot;1802&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 내부적으로 자동 형 변환(암시적 변환)을 수행하지만, &lt;b&gt;예외나 의도치 않은 결과가 발생할 수 있다&lt;/b&gt;. 따라서 아래와 같은 경우에는 명시적으로 CAST()를 사용하는 것이 안정적이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1978&quot; data-start=&quot;1916&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1937&quot; data-start=&quot;1916&quot;&gt;WHERE 절에서 날짜 비교 시&lt;/li&gt;
&lt;li data-end=&quot;1960&quot; data-start=&quot;1938&quot;&gt;JOIN 조건에서 타입이 다를 때&lt;/li&gt;
&lt;li data-end=&quot;1978&quot; data-start=&quot;1961&quot;&gt;JSON &amp;rarr; 문자열 변환 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1988&quot; data-start=&quot;1980&quot; data-ke-size=&quot;size26&quot;&gt;주의 사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2130&quot; data-start=&quot;1990&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2029&quot; data-start=&quot;1990&quot;&gt;타입이 유효하지 않거나 포맷이 맞지 않으면 &lt;b&gt;NULL 반환&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2090&quot; data-start=&quot;2030&quot;&gt;DECIMAL, CHAR, DATE는 자주 쓰이지만 정확한 길이 지정이 필요한 경우도 있다&lt;/li&gt;
&lt;li data-end=&quot;2130&quot; data-start=&quot;2091&quot;&gt;숫자형 CHAR &amp;rarr; SIGNED/DECIMAL 변환 시 소수점 주의&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2137&quot; data-start=&quot;2132&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2308&quot; data-start=&quot;2139&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2194&quot; data-start=&quot;2139&quot;&gt;CAST()는 SQL 표준 형 변환 함수로, 다양한 타입 간의 안정적인 변환을 지원한다.&lt;/li&gt;
&lt;li data-end=&quot;2255&quot; data-start=&quot;2195&quot;&gt;암시적 변환에 의존하기보다는 CAST()를 통해 &lt;b&gt;예측 가능한 쿼리 결과&lt;/b&gt;를 얻는 것이 좋다.&lt;/li&gt;
&lt;li data-end=&quot;2308&quot; data-start=&quot;2256&quot;&gt;실무에서는 연산, 비교, 정렬, JOIN 조건에서 &lt;b&gt;타입 오류 방지&lt;/b&gt;에 매우 유용하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2318&quot; data-start=&quot;2310&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2393&quot; data-start=&quot;2320&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast&lt;/a&gt;&lt;/p&gt;</description>
      <category>DB</category>
      <category>cast</category>
      <category>cast함수</category>
      <category>MYSQL</category>
      <category>MySQL문자숫자변환</category>
      <category>mysql실전쿼리</category>
      <category>mysql형변환</category>
      <category>SQL타입캐스팅</category>
      <category>데이터타입변환</category>
      <category>타입변환예제</category>
      <category>형변환</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1081</guid>
      <comments>https://monkeybusiness.tistory.com/1081#entry1081comment</comments>
      <pubDate>Fri, 25 Jul 2025 11:28:30 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] CASE WHEN으로 다중 조건 처리하기</title>
      <link>https://monkeybusiness.tistory.com/1079</link>
      <description>&lt;p data-end=&quot;325&quot; data-start=&quot;187&quot; data-ke-size=&quot;size16&quot;&gt;IF() 함수가 간단한 조건 분기에 적합하다면, 복잡한 조건을 처리하려면 &lt;b&gt;CASE WHEN 문&lt;/b&gt;이 훨씬 더 강력하다. CASE는 &lt;b&gt;다중 조건을 순차적으로 평가하고 그에 따라 다른 결과를 반환&lt;/b&gt;할 수 있는 대표적인 흐름 제어 구조다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A3qZh/btsPxY519Ov/nQoKvKbJtR6Yswsl3nVXV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A3qZh/btsPxY519Ov/nQoKvKbJtR6Yswsl3nVXV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A3qZh/btsPxY519Ov/nQoKvKbJtR6Yswsl3nVXV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA3qZh%2FbtsPxY519Ov%2FnQoKvKbJtR6Yswsl3nVXV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;539&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;340&quot; data-start=&quot;327&quot; data-ke-size=&quot;size26&quot;&gt;CASE 기본 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346653465&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CASE
    WHEN 조건1 THEN 결과1
    WHEN 조건2 THEN 결과2
    ...
    ELSE 기본값
END&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;505&quot; data-start=&quot;428&quot; data-ke-size=&quot;size16&quot;&gt;위에서부터 순서대로 조건을 검사하며, &lt;b&gt;가장 먼저 참이 되는 조건&lt;/b&gt;의 결과가 반환된다. 조건이 모두 거짓이면 ELSE절이 실행된다.&lt;/p&gt;
&lt;h2 data-end=&quot;528&quot; data-start=&quot;507&quot; data-ke-size=&quot;size26&quot;&gt;예제 1: 점수에 따른 학점 부여&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346660505&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT name, score,
       CASE
         WHEN score &amp;gt;= 90 THEN 'A'
         WHEN score &amp;gt;= 80 THEN 'B'
         WHEN score &amp;gt;= 70 THEN 'C'
         ELSE 'F'
       END AS grade
FROM students;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;786&quot; data-start=&quot;732&quot; data-ke-size=&quot;size16&quot;&gt;조건을 순차적으로 평가해 가장 알맞은 학점을 부여한다. IF() 중첩보다 가독성이 훨씬 좋다.&lt;/p&gt;
&lt;h2 data-end=&quot;805&quot; data-start=&quot;788&quot; data-ke-size=&quot;size26&quot;&gt;예제 2: 회원 등급 표시&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346667387&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT user_id, total_spent,
       CASE
         WHEN total_spent &amp;gt;= 100000 THEN 'VIP'
         WHEN total_spent &amp;gt;= 50000 THEN 'Gold'
         WHEN total_spent &amp;gt;= 10000 THEN 'Silver'
         ELSE 'Bronze'
       END AS membership
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1115&quot; data-start=&quot;1063&quot; data-ke-size=&quot;size16&quot;&gt;실제 서비스에서 많이 쓰이는 등급 분류 로직이다. 금액 기준으로 회원 상태를 구분할 수 있다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1147&quot; data-start=&quot;1117&quot; data-ke-size=&quot;size26&quot;&gt;CASE는 SELECT 외에도 어디서나 사용 가능&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1279&quot; data-start=&quot;1149&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1181&quot; data-start=&quot;1149&quot;&gt;&lt;b&gt;ORDER BY 절&lt;/b&gt;: 정렬 기준에 조건 부여&lt;/li&gt;
&lt;li data-end=&quot;1213&quot; data-start=&quot;1182&quot;&gt;&lt;b&gt;WHERE 절&lt;/b&gt;: 조건 자체를 동적으로 설정&lt;/li&gt;
&lt;li data-end=&quot;1245&quot; data-start=&quot;1214&quot;&gt;&lt;b&gt;UPDATE 문&lt;/b&gt;: 수정값을 조건적으로 처리&lt;/li&gt;
&lt;li data-end=&quot;1279&quot; data-start=&quot;1246&quot;&gt;&lt;b&gt;GROUP BY, HAVING 절&lt;/b&gt;에서도 응용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1312&quot; data-start=&quot;1281&quot; data-ke-size=&quot;size23&quot;&gt;예제 3: ORDER BY CASE로 커스텀 정렬&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346675176&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM products
ORDER BY
  CASE category
    WHEN '가전' THEN 1
    WHEN '가구' THEN 2
    ELSE 3
  END;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1473&quot; data-start=&quot;1434&quot; data-ke-size=&quot;size16&quot;&gt;지정한 순서대로 정렬하려면 CASE를 활용한 인덱스 정렬이 효과적이다.&lt;/p&gt;
&lt;h3 data-end=&quot;1503&quot; data-start=&quot;1475&quot; data-ke-size=&quot;size23&quot;&gt;예제 4: UPDATE 시 조건에 따른 변경&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346682009&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE orders
SET status = CASE
               WHEN shipped_at IS NOT NULL THEN '배송완료'
               WHEN paid_at IS NOT NULL THEN '결제완료'
               ELSE '결제대기'
             END;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1741&quot; data-start=&quot;1701&quot; data-ke-size=&quot;size16&quot;&gt;배송, 결제 여부에 따라 주문 상태를 한 번에 일괄 업데이트할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1757&quot; data-start=&quot;1743&quot; data-ke-size=&quot;size26&quot;&gt;CASE와 IF 차이&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1918&quot; data-start=&quot;1759&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;IF() 함수&lt;/td&gt;
&lt;td&gt;CASE WHEN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1850&quot; data-start=&quot;1822&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1829&quot; data-start=&quot;1822&quot;&gt;조건 수&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1838&quot; data-start=&quot;1829&quot;&gt;2개만 처리&lt;/td&gt;
&lt;td data-end=&quot;1850&quot; data-start=&quot;1838&quot; data-col-size=&quot;sm&quot;&gt;다중 조건 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1879&quot; data-start=&quot;1851&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1857&quot; data-start=&quot;1851&quot;&gt;가독성&lt;/td&gt;
&lt;td data-end=&quot;1867&quot; data-start=&quot;1857&quot; data-col-size=&quot;sm&quot;&gt;중첩 시 복잡&lt;/td&gt;
&lt;td data-end=&quot;1879&quot; data-start=&quot;1867&quot; data-col-size=&quot;sm&quot;&gt;구조적으로 명확&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1918&quot; data-start=&quot;1880&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1888&quot; data-start=&quot;1880&quot;&gt;실무 활용&lt;/td&gt;
&lt;td data-end=&quot;1896&quot; data-start=&quot;1888&quot; data-col-size=&quot;sm&quot;&gt;단순 조건&lt;/td&gt;
&lt;td data-end=&quot;1918&quot; data-start=&quot;1896&quot; data-col-size=&quot;sm&quot;&gt;분류, 정렬, 등급 등 복합 조건&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1953&quot; data-start=&quot;1920&quot; data-ke-size=&quot;size16&quot;&gt;CASE는 &lt;b&gt;조건이 3개 이상인 경우 무조건 권장&lt;/b&gt;된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1960&quot; data-start=&quot;1955&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2152&quot; data-start=&quot;1962&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2011&quot; data-start=&quot;1962&quot;&gt;CASE WHEN은 다중 조건을 순차적으로 평가하고 결과를 반환하는 구조이다.&lt;/li&gt;
&lt;li data-end=&quot;2049&quot; data-start=&quot;2012&quot;&gt;IF() 중첩보다 가독성이 좋아 실무에서 자주 사용된다.&lt;/li&gt;
&lt;li data-end=&quot;2107&quot; data-start=&quot;2050&quot;&gt;SELECT뿐 아니라 ORDER BY, UPDATE, WHERE 등 어디에서든 활용할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;2152&quot; data-start=&quot;2108&quot;&gt;등급 부여, 주문 상태 분기, 정렬 순서 정의 등에 탁월한 효과를 발휘한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2162&quot; data-start=&quot;2154&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2245&quot; data-start=&quot;2164&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#operator_case&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#operator_case&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2340&quot; data-start=&quot;2263&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>CASEWHEN</category>
      <category>CASE활용예제</category>
      <category>IF대안</category>
      <category>MYSQL</category>
      <category>MySQLCASE문</category>
      <category>MySQL흐름제어</category>
      <category>SQL등급분류</category>
      <category>다중조건처리</category>
      <category>조건별정렬</category>
      <category>쿼리조건처리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1079</guid>
      <comments>https://monkeybusiness.tistory.com/1079#entry1079comment</comments>
      <pubDate>Fri, 25 Jul 2025 10:45:16 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] NULLIF로 두 값 비교 후 조건 처리하기</title>
      <link>https://monkeybusiness.tistory.com/1078</link>
      <description>&lt;p data-end=&quot;346&quot; data-start=&quot;198&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 NULLIF() 함수는 &lt;b&gt;두 값을 비교해서 같으면 NULL을 반환하고, 다르면 첫 번째 값을 그대로 반환&lt;/b&gt;하는 특이한 흐름 제어 함수이다. 주로 &lt;b&gt;0 나누기 오류 방지&lt;/b&gt;, &lt;b&gt;조건적 NULL 처리&lt;/b&gt;, &lt;b&gt;중복 체크 회피&lt;/b&gt; 등에 사용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v7UUZ/btsPwXtxFiR/UXLDE6rFHhinmA0kiyKvCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v7UUZ/btsPwXtxFiR/UXLDE6rFHhinmA0kiyKvCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v7UUZ/btsPwXtxFiR/UXLDE6rFHhinmA0kiyKvCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv7UUZ%2FbtsPwXtxFiR%2FUXLDE6rFHhinmA0kiyKvCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;573&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;366&quot; data-start=&quot;348&quot; data-ke-size=&quot;size26&quot;&gt;NULLIF 함수 기본 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346492168&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NULLIF(값1, 값2)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;445&quot; data-start=&quot;395&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;421&quot; data-start=&quot;395&quot;&gt;값1 = 값2이면 NULL 반환.&lt;/li&gt;
&lt;li data-end=&quot;445&quot; data-start=&quot;422&quot;&gt;값1 &amp;ne; 값2이면 값1을 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;479&quot; data-start=&quot;447&quot; data-ke-size=&quot;size16&quot;&gt;이 단순한 로직이 다양한 실무에서 꽤 강력한 기능을 한다.&lt;/p&gt;
&lt;h3 data-end=&quot;506&quot; data-start=&quot;481&quot; data-ke-size=&quot;size23&quot;&gt;예제 1: 값이 같으면 NULL로 처리&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346498505&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT NULLIF(100, 100); -- 결과: NULL
SELECT NULLIF(100, 50);  -- 결과: 100&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;617&quot; data-start=&quot;593&quot; data-ke-size=&quot;size26&quot;&gt;0으로 나누기 방지: 실무 최강 활용법&lt;/h2&gt;
&lt;p data-end=&quot;671&quot; data-start=&quot;619&quot; data-ke-size=&quot;size16&quot;&gt;NULLIF는 &lt;b&gt;0으로 나눴을 때 발생하는 오류&lt;/b&gt;를 방지하기 위한 가장 흔한 방법이다.&lt;/p&gt;
&lt;h3 data-end=&quot;696&quot; data-start=&quot;673&quot; data-ke-size=&quot;size23&quot;&gt;예제 2: 나눗셈 계산 시 0 회피&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346516089&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT sales,
       targets,
       sales / NULLIF(targets, 0) AS 달성률
FROM sales_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;881&quot; data-start=&quot;798&quot; data-ke-size=&quot;size16&quot;&gt;targets가 0일 경우 NULLIF(targets, 0)는 NULL을 반환하므로 sales / NULL이 되어 오류 없이 처리된다.&lt;/p&gt;
&lt;h2 data-end=&quot;904&quot; data-start=&quot;883&quot; data-ke-size=&quot;size26&quot;&gt;조건적 NULL 반환: 중복 회피&lt;/h2&gt;
&lt;p data-end=&quot;971&quot; data-start=&quot;906&quot; data-ke-size=&quot;size16&quot;&gt;NULLIF를 사용하면 &lt;b&gt;특정 조건에서만 NULL로 대체&lt;/b&gt;할 수 있어, 중복된 데이터를 걸러낼 때도 유용하다.&lt;/p&gt;
&lt;h3 data-end=&quot;996&quot; data-start=&quot;973&quot; data-ke-size=&quot;size23&quot;&gt;예제 3: 최근 변경된 항목만 추출&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346526161&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *,
       NULLIF(current_value, previous_value) AS 변경여부
FROM version_tracking;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1145&quot; data-start=&quot;1096&quot; data-ke-size=&quot;size16&quot;&gt;변경이 없는 경우 NULL, 변경된 경우에만 current_value를 반환한다.&lt;/p&gt;
&lt;h2 data-end=&quot;1166&quot; data-start=&quot;1147&quot; data-ke-size=&quot;size26&quot;&gt;IF, IFNULL과의 차이점&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1398&quot; data-start=&quot;1168&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수명&lt;/td&gt;
&lt;td&gt;역할&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1310&quot; data-start=&quot;1269&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1284&quot; data-start=&quot;1269&quot;&gt;IF()&lt;/td&gt;
&lt;td data-end=&quot;1310&quot; data-start=&quot;1284&quot; data-col-size=&quot;sm&quot;&gt;조건에 따라 두 값 중 하나 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1355&quot; data-start=&quot;1311&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1326&quot; data-start=&quot;1311&quot;&gt;IFNULL()&lt;/td&gt;
&lt;td data-end=&quot;1355&quot; data-start=&quot;1326&quot; data-col-size=&quot;sm&quot;&gt;NULL일 경우 대체값 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1398&quot; data-start=&quot;1356&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1371&quot; data-start=&quot;1356&quot;&gt;&lt;b&gt;NULLIF()&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1398&quot; data-start=&quot;1371&quot; data-col-size=&quot;sm&quot;&gt;같으면 NULL, 다르면 첫 번째 값 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1464&quot; data-start=&quot;1400&quot; data-ke-size=&quot;size16&quot;&gt;NULLIF()는 &lt;b&gt;조건이 아닌 '두 값의 비교 결과'에 따라 NULL을 반환&lt;/b&gt;하는 점이 가장 큰 특징이다.&lt;/p&gt;
&lt;h2 data-end=&quot;1471&quot; data-start=&quot;1466&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1682&quot; data-start=&quot;1473&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1525&quot; data-start=&quot;1473&quot;&gt;NULLIF(a, b)는 a == b일 때 NULL, 아니면 a를 반환한다.&lt;/li&gt;
&lt;li data-end=&quot;1581&quot; data-start=&quot;1526&quot;&gt;주로 &lt;b&gt;0 나누기 방지&lt;/b&gt;, &lt;b&gt;조건부 NULL 처리&lt;/b&gt;, &lt;b&gt;변경값 탐지&lt;/b&gt;에 활용된다.&lt;/li&gt;
&lt;li data-end=&quot;1641&quot; data-start=&quot;1582&quot;&gt;IF나 IFNULL과 다르게 직접적인 비교 기반이며, &lt;b&gt;비교 결과 자체가 조건이 된다&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;1682&quot; data-start=&quot;1642&quot;&gt;실무에서 안정성과 유연성을 높이기 위한 고급 테크닉으로 널리 쓰인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1692&quot; data-start=&quot;1684&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;1777&quot; data-start=&quot;1694&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_nullif&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_nullif&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;1873&quot; data-start=&quot;1795&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>0나누기방지</category>
      <category>DB예외처리</category>
      <category>MYSQL</category>
      <category>mysql예제</category>
      <category>MySQL흐름제어</category>
      <category>NULLIF</category>
      <category>NULLIF활용</category>
      <category>SQL계산보완</category>
      <category>비교기반NULL</category>
      <category>조건부NULL</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1078</guid>
      <comments>https://monkeybusiness.tistory.com/1078#entry1078comment</comments>
      <pubDate>Fri, 25 Jul 2025 09:43:14 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] IFNULL로 NULL 값을 기본값으로 대체하기</title>
      <link>https://monkeybusiness.tistory.com/1077</link>
      <description>&lt;p data-end=&quot;358&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;데이터베이스에서 NULL은 &quot;값이 없음&quot;을 의미하지만, 그대로 출력되면 사용자에게 혼란을 줄 수 있다. 이럴 때 유용하게 사용하는 함수가 바로 &lt;b&gt;IFNULL()&lt;/b&gt;이다. IFNULL은 &lt;b&gt;NULL 값을 기본값으로 치환&lt;/b&gt;해주는 MySQL의 대표적인 흐름 제어 함수이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ecukuj/btsPwAL6xE6/cWjQ2LoHRRNBqc4Wl5FXTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ecukuj/btsPwAL6xE6/cWjQ2LoHRRNBqc4Wl5FXTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ecukuj/btsPwAL6xE6/cWjQ2LoHRRNBqc4Wl5FXTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fecukuj%2FbtsPwAL6xE6%2FcWjQ2LoHRRNBqc4Wl5FXTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;516&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;378&quot; data-start=&quot;360&quot; data-ke-size=&quot;size26&quot;&gt;IFNULL 함수 기본 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346384393&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IFNULL(표현식, 대체값)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;466&quot; data-start=&quot;409&quot; data-ke-size=&quot;size16&quot;&gt;표현식이 NULL이면 두 번째 인자인 대체값을 반환하고, NULL이 아니면 원래 값을 반환한다.&lt;/p&gt;
&lt;h3 data-end=&quot;491&quot; data-start=&quot;468&quot; data-ke-size=&quot;size23&quot;&gt;예제 1: 사용자 이름 기본값 설정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346389888&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT user_id, IFNULL(name, '이름없음') AS display_name
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;606&quot; data-start=&quot;570&quot; data-ke-size=&quot;size16&quot;&gt;사용자 이름이 NULL인 경우 '이름없음'으로 대체하여 출력한다.&lt;/p&gt;
&lt;h2 data-end=&quot;647&quot; data-start=&quot;608&quot; data-ke-size=&quot;size26&quot;&gt;IFNULL은 SELECT, WHERE, JOIN에서도 자주 사용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;766&quot; data-start=&quot;649&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;685&quot; data-start=&quot;649&quot;&gt;SELECT 결과에서 &lt;b&gt;NULL을 기본 문자열로 치환&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;726&quot; data-start=&quot;686&quot;&gt;숫자 계산 시 NULL을 &lt;b&gt;0이나 1로 바꿔 수식 오류 방지&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;766&quot; data-start=&quot;727&quot;&gt;LEFT JOIN 시, &lt;b&gt;존재하지 않는 값의 기본 대체&lt;/b&gt;로 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;793&quot; data-start=&quot;768&quot; data-ke-size=&quot;size23&quot;&gt;예제 2: 합계 계산 시 NULL 방지&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346397497&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT order_id,
       price,
       IFNULL(discount, 0) AS discount,
       price - IFNULL(discount, 0) AS actual_price
FROM orders;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;983&quot; data-start=&quot;942&quot; data-ke-size=&quot;size16&quot;&gt;discount가 NULL일 경우 0으로 간주해 계산을 안전하게 한다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1015&quot; data-start=&quot;985&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제 3: LEFT JOIN 후 기본값 설정&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346403800&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT a.id, a.name,
       IFNULL(b.phone, '없음') AS 전화번호
FROM customer a
LEFT JOIN customer_detail b ON a.id = b.id;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1190&quot; data-start=&quot;1147&quot; data-ke-size=&quot;size16&quot;&gt;조인된 테이블에 정보가 없을 경우, NULL 대신 '없음'을 표시할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1216&quot; data-start=&quot;1192&quot; data-ke-size=&quot;size26&quot;&gt;IFNULL vs COALESCE 차이&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1460&quot; data-start=&quot;1218&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수명&lt;/td&gt;
&lt;td&gt;특징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1402&quot; data-start=&quot;1341&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1356&quot; data-start=&quot;1341&quot;&gt;IFNULL(a, b)&lt;/td&gt;
&lt;td data-end=&quot;1402&quot; data-start=&quot;1356&quot; data-col-size=&quot;sm&quot;&gt;a가 NULL이면 b 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1460&quot; data-start=&quot;1403&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1426&quot; data-start=&quot;1403&quot;&gt;COALESCE(a, b, c...)&lt;/td&gt;
&lt;td data-end=&quot;1460&quot; data-start=&quot;1426&quot; data-col-size=&quot;sm&quot;&gt;NULL이 아닌 첫 번째 값을 반환 (2개 이상 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1526&quot; data-start=&quot;1462&quot; data-ke-size=&quot;size16&quot;&gt;IFNULL은 2개 인자만 처리 가능하지만, COALESCE는 여러 후보 중 첫 번째 NULL이 아닌 값을 고른다.&lt;/p&gt;
&lt;h3 data-end=&quot;1553&quot; data-start=&quot;1528&quot; data-ke-size=&quot;size23&quot;&gt;예제 4: 여러 필드에서 우선순위 지정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346427865&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT COALESCE(nickname, username, '익명') AS 표시이름
FROM member;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1690&quot; data-start=&quot;1630&quot; data-ke-size=&quot;size16&quot;&gt;순서대로 nickname &amp;rarr; username &amp;rarr; '익명'을 체크해 NULL이 아닌 값을 선택한다.&lt;/p&gt;
&lt;h2 data-end=&quot;1697&quot; data-start=&quot;1692&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1930&quot; data-start=&quot;1699&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1753&quot; data-start=&quot;1699&quot;&gt;IFNULL()은 NULL을 기본값으로 대체하는 함수로, 데이터 표시 안정성을 높인다.&lt;/li&gt;
&lt;li data-end=&quot;1806&quot; data-start=&quot;1754&quot;&gt;SELECT, JOIN, 계산식 등 다양한 위치에서 널 값을 안전하게 처리할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;1868&quot; data-start=&quot;1807&quot;&gt;IFNULL()은 COALESCE()보다 단순하지만 대부분의 경우 더 간단하게 사용할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;1930&quot; data-start=&quot;1869&quot;&gt;실무에서 사용자 정보, 할인 계산, 주소/연락처 정보 등 NULL이 자주 등장하는 곳에서 유용하게 쓰인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1940&quot; data-start=&quot;1932&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2025&quot; data-start=&quot;1942&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_ifnull&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_ifnull&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2123&quot; data-start=&quot;2043&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>COALESCE비교</category>
      <category>DB기본값처리</category>
      <category>ifnull</category>
      <category>IFNULL사용법</category>
      <category>MYSQL</category>
      <category>mysql예제</category>
      <category>MySQL흐름제어</category>
      <category>Null처리</category>
      <category>sqlnull</category>
      <category>기본값대체</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1077</guid>
      <comments>https://monkeybusiness.tistory.com/1077#entry1077comment</comments>
      <pubDate>Fri, 25 Jul 2025 08:40:48 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] IF 함수로 조건 분기 처리하는 법</title>
      <link>https://monkeybusiness.tistory.com/1076</link>
      <description>&lt;p data-end=&quot;346&quot; data-start=&quot;200&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 데이터를 조건에 따라 다르게 처리하려면 반드시 알아야 할 것이 바로 &lt;b&gt;IF 함수&lt;/b&gt;이다. IF()는 프로그래밍 언어의 if문과 비슷한 구조를 가지며, &lt;b&gt;조건식이 참인지 거짓인지에 따라 서로 다른 값을 반환&lt;/b&gt;하는 매우 유용한 제어 함수이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch4f1u/btsPyp9SySB/rUGqA6QdH6EtSsKRXbI2fK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch4f1u/btsPyp9SySB/rUGqA6QdH6EtSsKRXbI2fK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch4f1u/btsPyp9SySB/rUGqA6QdH6EtSsKRXbI2fK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch4f1u%2FbtsPyp9SySB%2FrUGqA6QdH6EtSsKRXbI2fK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;505&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;362&quot; data-start=&quot;348&quot; data-ke-size=&quot;size26&quot;&gt;IF 함수 기본 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346265297&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IF(조건식, 참일 때 반환값, 거짓일 때 반환값)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;455&quot; data-start=&quot;405&quot; data-ke-size=&quot;size16&quot;&gt;조건식이 TRUE면 두 번째 인자를 반환하고, 그렇지 않으면 세 번째 인자를 반환한다.&lt;/p&gt;
&lt;h3 data-end=&quot;482&quot; data-start=&quot;457&quot; data-ke-size=&quot;size23&quot;&gt;예제 1: 점수에 따른 합격 여부 표시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346271689&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT name, score,
       IF(score &amp;gt;= 60, '합격', '불합격') AS 결과
FROM exam_result;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;616&quot; data-start=&quot;576&quot; data-ke-size=&quot;size16&quot;&gt;score가 60점 이상이면 '합격', 아니면 '불합격'을 반환한다.&lt;/p&gt;
&lt;h2 data-end=&quot;647&quot; data-start=&quot;618&quot; data-ke-size=&quot;size26&quot;&gt;IF 함수는 SELECT 문 어디서나 사용 가능&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;786&quot; data-start=&quot;649&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;676&quot; data-start=&quot;649&quot;&gt;&lt;b&gt;SELECT 절&lt;/b&gt;에서 조건 분기 출력&lt;/li&gt;
&lt;li data-end=&quot;702&quot; data-start=&quot;677&quot;&gt;&lt;b&gt;WHERE 절&lt;/b&gt; 내부의 조건 처리&lt;/li&gt;
&lt;li data-end=&quot;732&quot; data-start=&quot;703&quot;&gt;&lt;b&gt;ORDER BY 절&lt;/b&gt;에서 정렬 조건 설정&lt;/li&gt;
&lt;li data-end=&quot;762&quot; data-start=&quot;733&quot;&gt;&lt;b&gt;UPDATE 문&lt;/b&gt;에서 컬럼 값 조건 처리&lt;/li&gt;
&lt;li data-end=&quot;786&quot; data-start=&quot;763&quot;&gt;&lt;b&gt;SET 절&lt;/b&gt;에서도 변수 제어 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;810&quot; data-start=&quot;788&quot; data-ke-size=&quot;size23&quot;&gt;예제 2: WHERE 절에서 사용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346279800&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM orders
WHERE IF(status = 'cancel', FALSE, TRUE);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;933&quot; data-start=&quot;887&quot; data-ke-size=&quot;size16&quot;&gt;주문 상태가 cancel이면 결과에서 제외하고, 그 외는 포함하는 조건 처리다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;954&quot; data-start=&quot;935&quot; data-ke-size=&quot;size26&quot;&gt;IF 함수는 중첩 사용도 가능&lt;/h2&gt;
&lt;p data-end=&quot;991&quot; data-start=&quot;956&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IF 문을 중첩하면 복잡한 조건 분기도 표현&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;1017&quot; data-start=&quot;993&quot; data-ke-size=&quot;size23&quot;&gt;예제 3: 등급 매기기 (중첩 IF)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346285880&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT name, score,
       IF(score &amp;gt;= 90, 'A',
          IF(score &amp;gt;= 80, 'B',
             IF(score &amp;gt;= 70, 'C', 'F'))) AS 등급
FROM students;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1216&quot; data-start=&quot;1172&quot; data-ke-size=&quot;size16&quot;&gt;점수에 따라 A/B/C/F 등급을 반환하며, 실무에서 자주 쓰이는 패턴이다.&lt;/p&gt;
&lt;h2 data-end=&quot;1241&quot; data-start=&quot;1218&quot; data-ke-size=&quot;size26&quot;&gt;IF 함수 vs WHERE 조건 비교&lt;/h2&gt;
&lt;p data-end=&quot;1291&quot; data-start=&quot;1243&quot; data-ke-size=&quot;size16&quot;&gt;IF()는 반환값을 선택할 때 쓰이고, WHERE은 행 자체의 필터링 조건이다.&lt;/p&gt;
&lt;h3 data-end=&quot;1309&quot; data-start=&quot;1293&quot; data-ke-size=&quot;size23&quot;&gt;예제 4: 할인율 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346294929&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT customer_id, amount,
       IF(amount &amp;gt;= 50000, amount * 0.9, amount) AS 할인적용금액
FROM purchases;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1459&quot; data-start=&quot;1426&quot; data-ke-size=&quot;size16&quot;&gt;금액이 크면 자동으로 할인을 적용하는 구조를 만들 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1471&quot; data-start=&quot;1461&quot; data-ke-size=&quot;size26&quot;&gt;실무 활용 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1601&quot; data-start=&quot;1473&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1506&quot; data-start=&quot;1473&quot;&gt;&lt;b&gt;쿼리 결과를 보기 좋게 표현할 때 필수적&lt;/b&gt;이다.&lt;/li&gt;
&lt;li data-end=&quot;1558&quot; data-start=&quot;1507&quot;&gt;&lt;b&gt;가공 컬럼 생성 시 많이 사용&lt;/b&gt;되며, IF 없이 CASE문으로 바꿀 수도 있다.&lt;/li&gt;
&lt;li data-end=&quot;1601&quot; data-start=&quot;1559&quot;&gt;조건 분기가 복잡해질수록 IF보다 CASE가 가독성에서 유리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1610&quot; data-start=&quot;1603&quot; data-ke-size=&quot;size26&quot;&gt;주의사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1762&quot; data-start=&quot;1612&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1649&quot; data-start=&quot;1612&quot;&gt;문자열 조건은 '값' 형태로 반드시 따옴표를 써야 한다.&lt;/li&gt;
&lt;li data-end=&quot;1702&quot; data-start=&quot;1650&quot;&gt;NULL 비교 시에는 IS NULL, IS NOT NULL 구문이 더 적합하다.&lt;/li&gt;
&lt;li data-end=&quot;1762&quot; data-start=&quot;1703&quot;&gt;IF()는 첫 번째 인자가 &lt;b&gt;논리값을 반환해야 한다&lt;/b&gt;. 수치 비교나 논리 연산자가 꼭 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1769&quot; data-start=&quot;1764&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1971&quot; data-start=&quot;1771&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1815&quot; data-start=&quot;1771&quot;&gt;IF()는 SQL에서 조건에 따라 다른 값을 반환하는 제어 함수이다.&lt;/li&gt;
&lt;li data-end=&quot;1867&quot; data-start=&quot;1816&quot;&gt;SELECT, WHERE, ORDER BY 등 다양한 구문 안에서 자유롭게 사용된다.&lt;/li&gt;
&lt;li data-end=&quot;1912&quot; data-start=&quot;1868&quot;&gt;실무에서는 등급 분류, 상태 표시, 금액 조건 처리 등에 자주 사용된다.&lt;/li&gt;
&lt;li data-end=&quot;1971&quot; data-start=&quot;1913&quot;&gt;중첩 IF를 통해 여러 조건을 순차적으로 평가할 수 있지만 복잡하면 CASE문으로 바꾸는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1981&quot; data-start=&quot;1973&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2062&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_if&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_if&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2150&quot; data-start=&quot;2080&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>IF문중첩</category>
      <category>IF함수</category>
      <category>MYSQL</category>
      <category>mysqlif</category>
      <category>mysql실무예제</category>
      <category>MySQL제어함수</category>
      <category>SQL분기처리</category>
      <category>SQL조건식</category>
      <category>조건분기</category>
      <category>쿼리조건문</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1076</guid>
      <comments>https://monkeybusiness.tistory.com/1076#entry1076comment</comments>
      <pubDate>Fri, 25 Jul 2025 01:50:48 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] PI, RAND, SIGN 등 특수 수학 함수 모음</title>
      <link>https://monkeybusiness.tistory.com/1075</link>
      <description>&lt;p data-end=&quot;405&quot; data-start=&quot;201&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에는 사칙 연산이나 삼각 함수 외에도 &lt;b&gt;특수한 수학 연산에 사용되는 내장 함수&lt;/b&gt;들이 존재한다. 이들은 데이터 분석, 무작위 처리, 방향 판단, 정규화 등에 자주 사용된다. 이번 글에서는 실무에서 유용하게 쓰이는 &lt;b&gt;PI(), RAND(), SIGN(), LEAST(), GREATEST(), ROUND()의 특수 사용법&lt;/b&gt; 등을 예제 중심으로 정리한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVjIZO/btsPwAdbedY/UJKDra68DszSomeZ5SJW3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVjIZO/btsPwAdbedY/UJKDra68DszSomeZ5SJW3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVjIZO/btsPwAdbedY/UJKDra68DszSomeZ5SJW3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVjIZO%2FbtsPwAdbedY%2FUJKDra68DszSomeZ5SJW3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;573&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;426&quot; data-start=&quot;407&quot; data-ke-size=&quot;size26&quot;&gt;PI() 함수 &amp;ndash; 원주율 상수&lt;/h2&gt;
&lt;p data-end=&quot;501&quot; data-start=&quot;428&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PI()&lt;/b&gt; 함수는 &lt;b&gt;수학 상수 &amp;pi;(파이)&lt;/b&gt; 값을 반환한다. 이는 원의 둘레, 면적, 각도 계산 등에서 필수적으로 사용된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329258524&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT PI(); -- 결과: 3.141592653589793&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;569&quot; data-start=&quot;553&quot; data-ke-size=&quot;size23&quot;&gt;예제: 원의 면적 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329263708&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT radius, PI() * POW(radius, 2) AS area
FROM circles;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;675&quot; data-start=&quot;642&quot; data-ke-size=&quot;size16&quot;&gt;반지름이 주어졌을 때 원의 넓이를 계산하는 수식에 활용된다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;701&quot; data-start=&quot;677&quot; data-ke-size=&quot;size26&quot;&gt;RAND() 함수 &amp;ndash; 무작위 난수 생성&lt;/h2&gt;
&lt;p data-end=&quot;782&quot; data-start=&quot;703&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RAND()&lt;/b&gt; 함수는 0 이상 1 미만의 **난수(random float)**를 반환한다. 시드 값을 지정하면 예측 가능한 값이 나온다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329274239&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT RAND();      -- 예: 0.31845...
SELECT RAND(100);   -- 같은 시드 &amp;rarr; 같은 결과&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;894&quot; data-start=&quot;870&quot; data-ke-size=&quot;size23&quot;&gt;예제: 1부터 100 사이 난수 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329279028&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FLOOR(RAND() * 100) + 1 AS random_number;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1026&quot; data-start=&quot;957&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 1~100 사이의 정수를 생성할 수 있다. &lt;b&gt;랜덤 추천, 테스트 데이터 생성, 샘플링&lt;/b&gt; 등에 매우 유용하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1048&quot; data-start=&quot;1028&quot; data-ke-size=&quot;size26&quot;&gt;SIGN() 함수 &amp;ndash; 부호 반환&lt;/h2&gt;
&lt;p data-end=&quot;1108&quot; data-start=&quot;1050&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SIGN(number)&lt;/b&gt; 함수는 입력 값이 &lt;b&gt;양수면 1, 음수면 -1, 0이면 0&lt;/b&gt;을 반환한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329285436&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SIGN(10);    -- 결과: 1
SELECT SIGN(-5.5);  -- 결과: -1
SELECT SIGN(0);     -- 결과: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1229&quot; data-start=&quot;1210&quot; data-ke-size=&quot;size23&quot;&gt;예제: 수익/손실 방향 표시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329294694&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT profit, SIGN(profit) AS direction
FROM sales_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1366&quot; data-start=&quot;1301&quot; data-ke-size=&quot;size16&quot;&gt;데이터의 &lt;b&gt;증가/감소 방향을 빠르게 판단&lt;/b&gt;할 수 있어, &lt;b&gt;차트 색상 처리나 시각화 조건 분기&lt;/b&gt;에 자주 쓰인다.&lt;/p&gt;
&lt;h2 data-end=&quot;1412&quot; data-start=&quot;1368&quot; data-ke-size=&quot;size26&quot;&gt;LEAST(), GREATEST() 함수 &amp;ndash; 다수 값 중 최소/최대 구하기&lt;/h2&gt;
&lt;p data-end=&quot;1478&quot; data-start=&quot;1414&quot; data-ke-size=&quot;size16&quot;&gt;이 함수들은 여러 인자 중 &lt;b&gt;가장 작은 값(LEAST)&lt;/b&gt; 또는 **가장 큰 값(GREATEST)**을 반환한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329299798&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LEAST(10, 25, 7);      -- 결과: 7
SELECT GREATEST(10, 25, 7);   -- 결과: 25&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1591&quot; data-start=&quot;1571&quot; data-ke-size=&quot;size23&quot;&gt;예제: 상품 가격 범위 필터링&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329304748&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT product_id,
       LEAST(price, max_limit) AS capped_price
FROM products;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1733&quot; data-start=&quot;1686&quot; data-ke-size=&quot;size16&quot;&gt;가격 상한선을 제한하거나, &lt;b&gt;최소/최대 비교로 조건을 제한&lt;/b&gt;할 때 매우 유용하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1755&quot; data-start=&quot;1735&quot; data-ke-size=&quot;size26&quot;&gt;실무 응용 예제: 데이터 정규화&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329312196&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT value,
       ROUND(value / GREATEST(max_val, 1), 2) AS normalized_value
FROM raw_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1949&quot; data-start=&quot;1864&quot; data-ke-size=&quot;size16&quot;&gt;GREATEST()를 이용해 0 나누기 오류를 방지하면서 정규화를 수행할 수 있다. &lt;b&gt;데이터 정제, AI 전처리, 지표 표준화&lt;/b&gt;에 자주 사용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1962&quot; data-start=&quot;1951&quot; data-ke-size=&quot;size26&quot;&gt;기타 유용 함수&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2138&quot; data-start=&quot;1964&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2021&quot; data-start=&quot;1964&quot;&gt;&lt;b&gt;ROUND(x)&lt;/b&gt;: 소수점 반올림 (이미 앞에서 다뤘지만, 정수 자리 반올림용으로도 쓰임)&lt;/li&gt;
&lt;li data-end=&quot;2056&quot; data-start=&quot;2022&quot;&gt;&lt;b&gt;CEIL(), FLOOR()&lt;/b&gt;: 올림, 내림 처리&lt;/li&gt;
&lt;li data-end=&quot;2093&quot; data-start=&quot;2057&quot;&gt;&lt;b&gt;TRUNCATE(x, d)&lt;/b&gt;: 특정 소수점 이하 절사&lt;/li&gt;
&lt;li data-end=&quot;2138&quot; data-start=&quot;2094&quot;&gt;&lt;b&gt;POWER(x, y)&lt;/b&gt; 또는 &lt;b&gt;POW(x, y)&lt;/b&gt;: x의 y제곱&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2179&quot; data-start=&quot;2140&quot; data-ke-size=&quot;size16&quot;&gt;이러한 함수들과 함께 쓰이면 계산 로직을 완성도 높게 설계할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;2186&quot; data-start=&quot;2181&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2441&quot; data-start=&quot;2188&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2232&quot; data-start=&quot;2188&quot;&gt;PI()는 원주율로, 면적&amp;middot;각도&amp;middot;좌표계 처리에 기본 상수로 활용된다.&lt;/li&gt;
&lt;li data-end=&quot;2284&quot; data-start=&quot;2233&quot;&gt;RAND()는 무작위 숫자를 생성하며, 테스트 데이터나 추천 기능에 자주 쓰인다.&lt;/li&gt;
&lt;li data-end=&quot;2333&quot; data-start=&quot;2285&quot;&gt;SIGN()은 숫자의 부호를 판단하여 방향성 분석, 시각화 로직에 유용하다.&lt;/li&gt;
&lt;li data-end=&quot;2390&quot; data-start=&quot;2334&quot;&gt;LEAST()와 GREATEST()는 다수의 값 중 최소/최대 비교에 최적화되어 있다.&lt;/li&gt;
&lt;li data-end=&quot;2441&quot; data-start=&quot;2391&quot;&gt;이 특수 함수들은 복잡한 연산을 간단하게 구현할 수 있는 &lt;b&gt;실무형 도구 모음&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2451&quot; data-start=&quot;2443&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2520&quot; data-start=&quot;2453&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2601&quot; data-start=&quot;2538&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB계산팁</category>
      <category>GREATEST</category>
      <category>least</category>
      <category>MYSQL</category>
      <category>MySQL수학함수</category>
      <category>pi</category>
      <category>rand</category>
      <category>Sign</category>
      <category>SQL수식정리</category>
      <category>무작위계산</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1075</guid>
      <comments>https://monkeybusiness.tistory.com/1075#entry1075comment</comments>
      <pubDate>Fri, 25 Jul 2025 00:40:19 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] RADIANS, DEGREES로 각도 변환하기</title>
      <link>https://monkeybusiness.tistory.com/1074</link>
      <description>&lt;p data-end=&quot;446&quot; data-start=&quot;193&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 삼각함수를 사용하려면 반드시 고려해야 할 것이 바로 &lt;b&gt;각도의 단위&lt;/b&gt;이다. 대부분의 사람은 도(degree) 단위로 각도를 생각하지만, &lt;b&gt;MySQL 삼각함수는 모두 라디안(radian) 단위를 사용&lt;/b&gt;한다. 따라서 &lt;b&gt;RADIANS()&lt;/b&gt;와 &lt;b&gt;DEGREES()&lt;/b&gt; 함수는 삼각함수 연산 전후에 꼭 함께 쓰이는 필수 유틸이다. 이 글에서는 이 두 함수를 활용해 &lt;b&gt;도 &amp;harr; 라디안 변환&lt;/b&gt;을 정확하고 효과적으로 처리하는 방법을 정리한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/piu7D/btsPxMjpxwm/0KmYLR4qjkPtXeu7qpKIWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/piu7D/btsPxMjpxwm/0KmYLR4qjkPtXeu7qpKIWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/piu7D/btsPxMjpxwm/0KmYLR4qjkPtXeu7qpKIWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpiu7D%2FbtsPxMjpxwm%2F0KmYLR4qjkPtXeu7qpKIWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;510&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;492&quot; data-start=&quot;448&quot; data-ke-size=&quot;size26&quot;&gt;RADIANS() 함수 &amp;ndash; 도(degree) &amp;rarr; 라디안(radian) 변환&lt;/h2&gt;
&lt;p data-end=&quot;544&quot; data-start=&quot;494&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RADIANS(degree)&lt;/b&gt; 함수는 입력한 각도를 &lt;b&gt;라디안 값으로 변환&lt;/b&gt;해준다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329162068&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT RADIANS(180); -- 결과: 3.141592...
SELECT RADIANS(90);  -- 결과: 1.570796...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;705&quot; data-start=&quot;638&quot; data-ke-size=&quot;size16&quot;&gt;기본 수학 공식은 라디안 = (&amp;pi; / 180) &amp;times; 각도이므로, RADIANS는 이 연산을 자동으로 처리해주는 함수다.&lt;/p&gt;
&lt;h3 data-end=&quot;728&quot; data-start=&quot;707&quot; data-ke-size=&quot;size23&quot;&gt;예제: 사인 계산 전 각도 변환&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329168420&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SIN(RADIANS(30)); -- 결과: 0.5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;824&quot; data-start=&quot;778&quot; data-ke-size=&quot;size16&quot;&gt;삼각함수에서 입력값을 직접 라디안으로 변환하지 않으면 엉뚱한 결과가 나올 수 있다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;870&quot; data-start=&quot;826&quot; data-ke-size=&quot;size26&quot;&gt;DEGREES() 함수 &amp;ndash; 라디안(radian) &amp;rarr; 도(degree) 변환&lt;/h2&gt;
&lt;p data-end=&quot;922&quot; data-start=&quot;872&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DEGREES(radian)&lt;/b&gt; 함수는 입력한 라디안 값을 &lt;b&gt;도 단위로 변환&lt;/b&gt;한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329175468&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DEGREES(PI());     -- 결과: 180
SELECT DEGREES(PI() / 2); -- 결과: 90&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1068&quot; data-start=&quot;1009&quot; data-ke-size=&quot;size16&quot;&gt;기본 공식은 각도 = (180 / &amp;pi;) &amp;times; 라디안이며, DEGREES는 이 연산을 자동으로 수행해준다.&lt;/p&gt;
&lt;h3 data-end=&quot;1102&quot; data-start=&quot;1070&quot; data-ke-size=&quot;size23&quot;&gt;예제: ATAN2로 구한 각도 라디안 &amp;rarr; 도로 변환&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329182055&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DEGREES(ATAN2(10, 10)); -- 결과: 45&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1208&quot; data-start=&quot;1157&quot; data-ke-size=&quot;size16&quot;&gt;많은 역삼각함수의 결과는 라디안이므로, 사람이 읽기 쉬운 각도로 바꿔야 할 때 꼭 필요하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1237&quot; data-start=&quot;1210&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제 1: 각도 기반의 원형 좌표 계산&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329187740&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  COS(RADIANS(angle)) * radius AS x,
  SIN(RADIANS(angle)) * radius AS y
FROM circular_points;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1432&quot; data-start=&quot;1353&quot; data-ke-size=&quot;size16&quot;&gt;RADIANS()를 사용하지 않으면 angle = 90 입력 시 COS(90)이 아니라 COS(90 라디안)으로 잘못 처리된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1466&quot; data-start=&quot;1434&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제 2: 센서 또는 GIS 데이터를 도로 표현&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329196391&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT id,
       heading_radian,
       DEGREES(heading_radian) AS heading_degree
FROM gps_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1629&quot; data-start=&quot;1578&quot; data-ke-size=&quot;size16&quot;&gt;기기에서 라디안 단위로 측정된 방향 데이터를 사용자 인터페이스에 도 단위로 표시할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1636&quot; data-start=&quot;1631&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1944&quot; data-start=&quot;1638&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1684&quot; data-start=&quot;1638&quot;&gt;RADIANS(degree)는 도 단위를 삼각함수용 라디안으로 변환한다.&lt;/li&gt;
&lt;li data-end=&quot;1736&quot; data-start=&quot;1685&quot;&gt;DEGREES(radian)는 라디안 단위를 사람이 읽을 수 있는 도로 바꿔준다.&lt;/li&gt;
&lt;li data-end=&quot;1823&quot; data-start=&quot;1737&quot;&gt;모든 SIN(), COS(), TAN(), ASIN() 등의 삼각함수는 &lt;b&gt;라디안 기준&lt;/b&gt;이므로 RADIANS()로 감싸야 한다.&lt;/li&gt;
&lt;li data-end=&quot;1901&quot; data-start=&quot;1824&quot;&gt;ATAN2(), ASIN() 등의 결과값은 라디안이므로 결과를 도로 보고 싶다면 DEGREES()로 다시 변환해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;1944&quot; data-start=&quot;1902&quot;&gt;&lt;b&gt;삼각함수와 각도 관련 연산에는 이 두 함수가 반드시 함께 쓰인다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1954&quot; data-start=&quot;1946&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2127&quot; data-start=&quot;1956&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_radians&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_radians&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_degrees&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_degrees&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2215&quot; data-start=&quot;2145&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB수학함수</category>
      <category>degrees</category>
      <category>MYSQL</category>
      <category>MySQL함수정리</category>
      <category>radians</category>
      <category>SQL좌표계산</category>
      <category>각도계산기</category>
      <category>각도변환</category>
      <category>라디안변환</category>
      <category>삼각함수보조</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1074</guid>
      <comments>https://monkeybusiness.tistory.com/1074#entry1074comment</comments>
      <pubDate>Thu, 24 Jul 2025 23:53:32 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] ASIN, ACOS, ATAN 역삼각함수 활용법</title>
      <link>https://monkeybusiness.tistory.com/1073</link>
      <description>&lt;p data-end=&quot;448&quot; data-start=&quot;200&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 일반적인 삼각함수뿐만 아니라 &lt;b&gt;역삼각함수(Inverse Trigonometric Functions)&lt;/b&gt;도 지원한다. 이는 사인, 코사인, 탄젠트 값을 주고 &lt;b&gt;각도(라디안)를 구할 때&lt;/b&gt; 사용하는 함수들로, MySQL에서는 &lt;b&gt;ASIN()&lt;/b&gt;, &lt;b&gt;ACOS()&lt;/b&gt;, &lt;b&gt;ATAN()&lt;/b&gt;으로 제공된다. 이 함수들은 주로 &lt;b&gt;각도 역산&lt;/b&gt;, &lt;b&gt;좌표계 방향 계산&lt;/b&gt;, &lt;b&gt;경사도 추출&lt;/b&gt;, &lt;b&gt;기하 계산&lt;/b&gt; 등에 활용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AooMK/btsPw0PYerD/GkONbSEG2okNvN4KZynMhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AooMK/btsPw0PYerD/GkONbSEG2okNvN4KZynMhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AooMK/btsPw0PYerD/GkONbSEG2okNvN4KZynMhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAooMK%2FbtsPw0PYerD%2FGkONbSEG2okNvN4KZynMhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;539&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;484&quot; data-start=&quot;450&quot; data-ke-size=&quot;size26&quot;&gt;ASIN() 함수 &amp;ndash; 아크사인 (inverse sine)&lt;/h2&gt;
&lt;p data-end=&quot;572&quot; data-start=&quot;486&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ASIN(x)&lt;/b&gt; 함수는 사인 값 x에 대한 &lt;b&gt;아크사인(asin), 즉 x가 어느 각도의 사인인지&lt;/b&gt;를 &lt;b&gt;라디안(radian)&lt;/b&gt;으로 반환한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329015597&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ASIN(0.5);     -- 결과: 약 0.523 라디안
SELECT DEGREES(ASIN(0.5)); -- 결과: 30&amp;deg;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;716&quot; data-start=&quot;665&quot; data-ke-size=&quot;size16&quot;&gt;입력 값의 유효 범위는 -1 &amp;le; x &amp;le; 1이다. 범위를 벗어나면 NULL이 반환된다.&lt;/p&gt;
&lt;h3 data-end=&quot;738&quot; data-start=&quot;718&quot; data-ke-size=&quot;size23&quot;&gt;예제: 사인값으로 각도 구하기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329020741&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT angle_value,
       DEGREES(ASIN(angle_value)) AS 각도
FROM angle_table
WHERE angle_value BETWEEN -1 AND 1;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;912&quot; data-start=&quot;865&quot; data-ke-size=&quot;size16&quot;&gt;센서 데이터나 회전값 등에서 &lt;b&gt;사인값으로부터 원래 각도를 역추적할 때 유용&lt;/b&gt;하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;951&quot; data-start=&quot;914&quot; data-ke-size=&quot;size26&quot;&gt;ACOS() 함수 &amp;ndash; 아크코사인 (inverse cosine)&lt;/h2&gt;
&lt;p data-end=&quot;1017&quot; data-start=&quot;953&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ACOS(x)&lt;/b&gt; 함수는 코사인 값 x에 대한 &lt;b&gt;아크코사인(acos)&lt;/b&gt; 값을 &lt;b&gt;라디안&lt;/b&gt;으로 반환한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329027620&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ACOS(0.5);     -- 결과: 약 1.047 라디안
SELECT DEGREES(ACOS(0.5)); -- 결과: 60&amp;deg;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1175&quot; data-start=&quot;1110&quot; data-ke-size=&quot;size16&quot;&gt;ACOS도 입력 값 범위는 -1 &amp;le; x &amp;le; 1이며, 보통 cos(&amp;theta;) = x 관계에서 &amp;theta;를 구할 때 사용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;1199&quot; data-start=&quot;1177&quot; data-ke-size=&quot;size23&quot;&gt;예제: 두 벡터 사이 각도 구하기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329033044&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DEGREES(ACOS(dot_product / (length1 * length2))) AS 벡터사이각도
FROM vector_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1355&quot; data-start=&quot;1297&quot; data-ke-size=&quot;size16&quot;&gt;코사인을 활용한 벡터 각도 공식으로, &lt;b&gt;2D/3D 좌표 계산이나 게임 엔진 수식 구현에도 활용&lt;/b&gt;된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1395&quot; data-start=&quot;1357&quot; data-ke-size=&quot;size26&quot;&gt;ATAN() 함수 &amp;ndash; 아크탄젠트 (inverse tangent)&lt;/h2&gt;
&lt;p data-end=&quot;1501&quot; data-start=&quot;1397&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ATAN(x)&lt;/b&gt; 함수는 탄젠트 값 x에 대한 &lt;b&gt;아크탄젠트(atan)&lt;/b&gt; 값을 라디안으로 반환한다. x = y / x와 같은 경사비(기울기)를 이용해 각도를 구할 때 쓰인다.&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329042701&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ATAN(1);       -- 결과: 약 0.785 라디안
SELECT DEGREES(ATAN(1)); -- 결과: 45&amp;deg;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1615&quot; data-start=&quot;1592&quot; data-ke-size=&quot;size23&quot;&gt;예제: 높이와 밑변으로 각도 구하기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329056220&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT height, width,
       DEGREES(ATAN(height / width)) AS 경사각도
FROM slope_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1765&quot; data-start=&quot;1713&quot; data-ke-size=&quot;size16&quot;&gt;길이로부터 기울기를 계산해 &lt;b&gt;경사도, 탄도 계산, 지도 데이터 처리&lt;/b&gt; 등에 자주 활용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1788&quot; data-start=&quot;1767&quot; data-ke-size=&quot;size26&quot;&gt;확장 함수: ATAN2(y, x)&lt;/h2&gt;
&lt;p data-end=&quot;1865&quot; data-start=&quot;1790&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 ATAN2(y, x) 함수도 지원한다. 이는 y축과 x축 길이를 받아 정확한 &lt;b&gt;사분면 기준 각도 계산&lt;/b&gt;을 수행한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329082996&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DEGREES(ATAN2(10, 10)); -- 결과: 45&amp;deg;
SELECT DEGREES(ATAN2(-10, -10)); -- 결과: -135&amp;deg;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2038&quot; data-start=&quot;1967&quot; data-ke-size=&quot;size16&quot;&gt;ATAN(y/x)는 부호가 모두 양수인지 음수인지 모르면 사분면 판별이 안 되는데, ATAN2()는 이 문제를 해결한다.&lt;/p&gt;
&lt;h3 data-end=&quot;2060&quot; data-start=&quot;2040&quot; data-ke-size=&quot;size23&quot;&gt;예제: 사용자 위치 각도 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753329090780&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT user_id,
       DEGREES(ATAN2(y2 - y1, x2 - x1)) AS 이동방향
FROM movement;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2215&quot; data-start=&quot;2153&quot; data-ke-size=&quot;size16&quot;&gt;위치 기반 시스템에서 두 지점 사이의 &lt;b&gt;방향 벡터를 각도로 변환&lt;/b&gt;할 수 있어 GPS 기반 앱에서도 활용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;2222&quot; data-start=&quot;2217&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2501&quot; data-start=&quot;2224&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2261&quot; data-start=&quot;2224&quot;&gt;ASIN(x)는 x가 사인일 때의 라디안 각도를 구한다.&lt;/li&gt;
&lt;li data-end=&quot;2300&quot; data-start=&quot;2262&quot;&gt;ACOS(x)는 x가 코사인일 때의 라디안 각도를 구한다.&lt;/li&gt;
&lt;li data-end=&quot;2337&quot; data-start=&quot;2301&quot;&gt;ATAN(x)는 기울기(탄젠트값)로부터 각도를 구한다.&lt;/li&gt;
&lt;li data-end=&quot;2394&quot; data-start=&quot;2338&quot;&gt;ATAN2(y, x)는 정확한 사분면 각도를 반환하며, 실무에서 ATAN보다 더 선호된다.&lt;/li&gt;
&lt;li data-end=&quot;2459&quot; data-start=&quot;2395&quot;&gt;모두 반환값은 라디안이므로 사람이 읽을 수 있는 각도로 바꾸려면 DEGREES()를 함께 사용해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2501&quot; data-start=&quot;2460&quot;&gt;역삼각함수는 각도를 복원하거나 위치&amp;middot;방향 연산에 매우 중요한 도구이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2511&quot; data-start=&quot;2503&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2847&quot; data-start=&quot;2513&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_asin&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_asin&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_acos&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_acos&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_atan&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_atan&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_atan2&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_atan2&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2926&quot; data-start=&quot;2865&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>ACOS</category>
      <category>asin</category>
      <category>atan</category>
      <category>atan2</category>
      <category>DB수학연산</category>
      <category>MYSQL</category>
      <category>MySQL공식정리</category>
      <category>SQL기울기</category>
      <category>각도계산</category>
      <category>역삼각함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1073</guid>
      <comments>https://monkeybusiness.tistory.com/1073#entry1073comment</comments>
      <pubDate>Thu, 24 Jul 2025 22:51:49 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] SIN, COS, TAN 삼각함수 완전 정리  </title>
      <link>https://monkeybusiness.tistory.com/1072</link>
      <description>&lt;p data-end=&quot;450&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;삼각함수는 수학, 물리, 그래픽, 위치 계산 등 다양한 분야에서 핵심적인 역할을 한다. MySQL에서도 이를 위해 &lt;b&gt;SIN()&lt;/b&gt;, &lt;b&gt;COS()&lt;/b&gt;, &lt;b&gt;TAN()&lt;/b&gt;과 같은 삼각함수를 지원한다. 이 함수들은 단독으로 쓰이는 경우는 드물지만, &lt;b&gt;좌표계 연산, 경로 계산, 데이터 시각화&lt;/b&gt;, 나아가 &lt;b&gt;3D 공간 계산&lt;/b&gt;에서도 유용하게 쓰인다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mwdPT/btsPxDz5Yy3/oJZqptufTH4vjan8qj6xKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mwdPT/btsPxDz5Yy3/oJZqptufTH4vjan8qj6xKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mwdPT/btsPxDz5Yy3/oJZqptufTH4vjan8qj6xKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmwdPT%2FbtsPxDz5Yy3%2FoJZqptufTH4vjan8qj6xKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;539&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;478&quot; data-start=&quot;452&quot; data-ke-size=&quot;size26&quot;&gt;삼각함수 입력 단위는 라디안(Radian)&lt;/h2&gt;
&lt;p data-end=&quot;612&quot; data-start=&quot;480&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 모든 삼각함수는 &lt;b&gt;각도를 '라디안' 단위로 입력받는다&lt;/b&gt;. 즉, &lt;b&gt;90도는 &amp;pi;/2 라디안&lt;/b&gt;, &lt;b&gt;180도는 &amp;pi; 라디안&lt;/b&gt;이다. 만약 도(degree) 단위를 사용하고 싶다면 RADIANS() 함수로 변환해야 한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328844956&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SIN(RADIANS(30));  -- 결과: 약 0.5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;665&quot; data-ke-size=&quot;size16&quot;&gt;이를 명심하지 않으면 삼각함수 결과가 전혀 다른 값이 나올 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;721&quot; data-start=&quot;705&quot; data-ke-size=&quot;size26&quot;&gt;SIN() 함수 &amp;ndash; 사인&lt;/h2&gt;
&lt;p data-end=&quot;835&quot; data-start=&quot;723&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SIN(x)&lt;/b&gt; 함수는 주어진 라디안 값 x에 대한 &lt;b&gt;사인 값(sine)&lt;/b&gt;을 반환한다. 사인 함수는 &lt;b&gt;직각삼각형에서 높이/빗변&lt;/b&gt;의 비율로 정의되며, 주기적인 변화를 표현할 때 자주 사용된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328851564&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SIN(RADIANS(90)); -- 결과: 1
SELECT SIN(RADIANS(0));  -- 결과: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;932&quot; data-start=&quot;917&quot; data-ke-size=&quot;size23&quot;&gt;예제: 파형 값 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328857284&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT i,
       SIN(RADIANS(i * 10)) AS sin_wave
FROM generate_series AS i
WHERE i BETWEEN 0 AND 36;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1113&quot; data-start=&quot;1048&quot; data-ke-size=&quot;size16&quot;&gt;0도부터 360도까지 10도 단위로 사인값을 구하면 &lt;b&gt;파형 형태 데이터를 만들 수 있어 그래프 처리에 유용&lt;/b&gt;하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1132&quot; data-start=&quot;1115&quot; data-ke-size=&quot;size26&quot;&gt;COS() 함수 &amp;ndash; 코사인&lt;/h2&gt;
&lt;p data-end=&quot;1243&quot; data-start=&quot;1134&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;COS(x)&lt;/b&gt; 함수는 주어진 라디안 값 x에 대한 &lt;b&gt;코사인 값(cosine)&lt;/b&gt;을 반환한다. &lt;b&gt;밑변/빗변&lt;/b&gt;의 비율로 정의되며, 사인과 함께 주기 함수를 만들거나 방향 계산에서 사용된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328866460&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT COS(RADIANS(60)); -- 결과: 약 0.5
SELECT COS(RADIANS(0));  -- 결과: 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1348&quot; data-start=&quot;1329&quot; data-ke-size=&quot;size23&quot;&gt;예제: 2D 원형 좌표 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328872797&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
  COS(RADIANS(angle)) * r AS x,
  SIN(RADIANS(angle)) * r AS y
FROM angles;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1531&quot; data-start=&quot;1446&quot; data-ke-size=&quot;size16&quot;&gt;사인과 코사인을 조합하면&lt;b&gt; 원형 좌표계(x, y)&lt;/b&gt;를 만들 수 있어 &lt;b&gt;레이더 차트, 원형 그래프, 게임 캐릭터 이동 경로&lt;/b&gt; 등을 구현할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1550&quot; data-start=&quot;1533&quot; data-ke-size=&quot;size26&quot;&gt;TAN() 함수 &amp;ndash; 탄젠트&lt;/h2&gt;
&lt;p data-end=&quot;1675&quot; data-start=&quot;1552&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TAN(x)&lt;/b&gt; 함수는 주어진 라디안 값 x에 대한 &lt;b&gt;탄젠트 값(tangent)&lt;/b&gt;을 반환한다. 탄젠트는 &lt;b&gt;높이/밑변&lt;/b&gt;, 즉 SIN(x)/COS(x)로 정의된다. 경사도 계산, 회전 각도 계산 등에 유용하다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328881333&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TAN(RADIANS(45));  -- 결과: 1
SELECT TAN(RADIANS(0));   -- 결과: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1773&quot; data-start=&quot;1759&quot; data-ke-size=&quot;size23&quot;&gt;예제: 경사도 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328886476&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT height / width AS 탄젠트값,
       DEGREES(ATAN(height / width)) AS 경사도_각도
FROM ramps;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1936&quot; data-start=&quot;1877&quot; data-ke-size=&quot;size16&quot;&gt;TAN은 ATAN()의 반대 함수로써, &lt;b&gt;경사비로부터 각도를 유추하는 계산 과정의 일부로 쓰인다&lt;/b&gt;.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1954&quot; data-start=&quot;1938&quot; data-ke-size=&quot;size26&quot;&gt;삼각함수 실무 활용 예시&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2140&quot; data-start=&quot;1956&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2011&quot; data-start=&quot;1956&quot;&gt;&lt;b&gt;경로 계산&lt;/b&gt;: 위도/경도 기반 거리 계산 (Haversine 공식을 구성할 때 사용)&lt;/li&gt;
&lt;li data-end=&quot;2052&quot; data-start=&quot;2012&quot;&gt;&lt;b&gt;좌표 변환&lt;/b&gt;: 도넛 차트, 파형 데이터, 그래픽 위치 처리&lt;/li&gt;
&lt;li data-end=&quot;2097&quot; data-start=&quot;2053&quot;&gt;&lt;b&gt;3D 게임 또는 지도 뷰&lt;/b&gt;: 물체 회전, 방향 계산, 시야각 구현&lt;/li&gt;
&lt;li data-end=&quot;2140&quot; data-start=&quot;2098&quot;&gt;&lt;b&gt;IoT 센서 데이터 분석&lt;/b&gt;: 회전 센서, 각도 센서의 출력값 분석&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-end=&quot;2149&quot; data-start=&quot;2142&quot; data-ke-size=&quot;size26&quot;&gt;주의사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2366&quot; data-start=&quot;2151&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2216&quot; data-start=&quot;2151&quot;&gt;입력은 &lt;b&gt;도(degree)&lt;/b&gt;가 아니라 &lt;b&gt;라디안(radian)&lt;/b&gt;이므로 RADIANS(x)로 변환 필수&lt;/li&gt;
&lt;li data-end=&quot;2302&quot; data-start=&quot;2217&quot;&gt;TAN(x)는 x = 90&amp;deg;, 270&amp;deg;처럼 COS(x) = 0일 경우 &lt;b&gt;무한대 값(INF)&lt;/b&gt; 또는 &lt;b&gt;NULL&lt;/b&gt;이 반환될 수 있음&lt;/li&gt;
&lt;li data-end=&quot;2366&quot; data-start=&quot;2303&quot;&gt;실무에서는 SIN(), COS()는 함께 쓰는 경우가 많고, TAN()은 제한적인 상황에서 사용된다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2373&quot; data-start=&quot;2368&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2610&quot; data-start=&quot;2375&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2438&quot; data-start=&quot;2375&quot;&gt;SIN(), COS(), TAN()은 각도 기반의 연산에 사용하는 대표적인 &lt;b&gt;삼각함수&lt;/b&gt;이다.&lt;/li&gt;
&lt;li data-end=&quot;2504&quot; data-start=&quot;2439&quot;&gt;MySQL에서는 &lt;b&gt;모든 삼각함수 입력은 라디안 단위&lt;/b&gt;이며, RADIANS()를 꼭 함께 사용해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2555&quot; data-start=&quot;2505&quot;&gt;파형 생성, 좌표계 처리, 회전 각도 계산, 데이터 시각화 등 실무 활용도가 높다.&lt;/li&gt;
&lt;li data-end=&quot;2610&quot; data-start=&quot;2556&quot;&gt;삼각함수는 단순 계산 외에도 &lt;b&gt;시계열 표현, 그래픽 계산, 방향성 처리&lt;/b&gt;에 매우 유용하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2620&quot; data-start=&quot;2612&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2868&quot; data-start=&quot;2622&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_sin&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_sin&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_cos&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_cos&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_tan&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_tan&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2944&quot; data-start=&quot;2886&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>cos</category>
      <category>DB수학함수</category>
      <category>MYSQL</category>
      <category>MySQL삼각함수</category>
      <category>sin</category>
      <category>sql함수정리</category>
      <category>tan</category>
      <category>각도계산</category>
      <category>그래픽좌표</category>
      <category>회전처리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1072</guid>
      <comments>https://monkeybusiness.tistory.com/1072#entry1072comment</comments>
      <pubDate>Thu, 24 Jul 2025 21:49:09 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] SQRT, EXP, LOG로 제곱근과 로그 구하기</title>
      <link>https://monkeybusiness.tistory.com/1071</link>
      <description>&lt;p data-end=&quot;382&quot; data-start=&quot;198&quot; data-ke-size=&quot;size16&quot;&gt;MySQL은 단순한 데이터 조회뿐 아니라 &lt;b&gt;수학적 계산&lt;/b&gt;도 가능하다. 특히 통계 분석, 수치 예측, 금융 수학 등에서 자주 사용하는 함수들이 바로 &lt;b&gt;제곱근(SQRT)&lt;/b&gt;, &lt;b&gt;지수(EXP)&lt;/b&gt;, &lt;b&gt;로그(LOG)&lt;/b&gt; 함수다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r5Lui/btsPwAxsZHY/rdRtC2WcYxxV6mObKxoSk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r5Lui/btsPwAxsZHY/rdRtC2WcYxxV6mObKxoSk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r5Lui/btsPwAxsZHY/rdRtC2WcYxxV6mObKxoSk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr5Lui%2FbtsPwAxsZHY%2FrdRtC2WcYxxV6mObKxoSk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;409&quot; data-start=&quot;384&quot; data-ke-size=&quot;size26&quot;&gt;SQRT() 함수 &amp;ndash; 제곱근(&amp;radic;) 구하기&lt;/h2&gt;
&lt;p data-end=&quot;504&quot; data-start=&quot;411&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SQRT(number)&lt;/b&gt; 함수는 주어진 수의 &lt;b&gt;제곱근(square root)&lt;/b&gt;을 반환한다. 즉, 어떤 수를 제곱했을 때 원래 수가 되는 수를 계산하는 것이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328662023&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SQRT(25);   -- 결과: 5
SELECT SQRT(2);    -- 결과: 1.4142...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;652&quot; data-start=&quot;582&quot; data-ke-size=&quot;size16&quot;&gt;음수 입력 시에는 NULL이 반환된다. 제곱근은 &lt;b&gt;거리 계산, 표준편차 계산, 통계 그래프 처리&lt;/b&gt; 등에 자주 사용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;675&quot; data-start=&quot;654&quot; data-ke-size=&quot;size23&quot;&gt;예제: 두 점 사이의 거리 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328667332&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SQRT(POW(x2 - x1, 2) + POW(y2 - y1, 2)) AS 거리
FROM points;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;807&quot; data-start=&quot;755&quot; data-ke-size=&quot;size16&quot;&gt;피타고라스 정리를 활용한 거리 계산 공식이다. 지도 기반 서비스, 그래픽 계산 등에 응용된다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;833&quot; data-start=&quot;809&quot; data-ke-size=&quot;size26&quot;&gt;EXP() 함수 &amp;ndash; 지수 계산 (eⁿ)&lt;/h2&gt;
&lt;p data-end=&quot;926&quot; data-start=&quot;835&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EXP(n)&lt;/b&gt; 함수는 자연상수 &lt;b&gt;e(약 2.71828)&lt;/b&gt;의 n 제곱 값을 반환한다. 이는 지수함수의 핵심이며, 복리, 성장률, 확률 계산에 자주 사용된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328677812&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT EXP(1);     -- 결과: 2.7182818...
SELECT EXP(2);     -- 결과: 7.389...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1038&quot; data-start=&quot;1014&quot; data-ke-size=&quot;size16&quot;&gt;EXP(x)는 곧 e^x를 의미한다.&lt;/p&gt;
&lt;h3 data-end=&quot;1063&quot; data-start=&quot;1040&quot; data-ke-size=&quot;size23&quot;&gt;예제: 복리 계산 공식의 지수 부분&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328686644&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT principal * EXP(rate * years) AS 최종금액
FROM investment;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1209&quot; data-start=&quot;1139&quot; data-ke-size=&quot;size16&quot;&gt;복리 공식 P * e^(rt)를 SQL로 구현한 형태이다. 금융 시스템에서 &lt;b&gt;복리 성장 모델을 직접 구현&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1235&quot; data-start=&quot;1211&quot; data-ke-size=&quot;size26&quot;&gt;LOG() 함수 &amp;ndash; 로그 계산 (ln)&lt;/h2&gt;
&lt;p data-end=&quot;1365&quot; data-start=&quot;1237&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LOG(n)&lt;/b&gt; 함수는 n의 &lt;b&gt;자연 로그(natural logarithm)&lt;/b&gt;, 즉 &lt;b&gt;밑이 e인 로그&lt;/b&gt;를 반환한다. 이 함수는 EXP의 역함수이며, 곱셈 &amp;rarr; 덧셈으로 변환하거나, 성장률 계산, 정규분포 처리 등에 쓰인다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328701652&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LOG(1);     -- 결과: 0
SELECT LOG(100);   -- 결과: 약 4.605&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1490&quot; data-start=&quot;1441&quot; data-ke-size=&quot;size16&quot;&gt;LOG 함수의 입력 값은 0보다 커야 하며, 음수나 0을 넣으면 NULL이 반환된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1527&quot; data-start=&quot;1492&quot; data-ke-size=&quot;size26&quot;&gt;LOG10(), LOG2() &amp;ndash; 밑이 10 또는 2인 로그&lt;/h2&gt;
&lt;p data-end=&quot;1609&quot; data-start=&quot;1529&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 &lt;b&gt;밑이 10인 로그&lt;/b&gt;를 구하는 &lt;b&gt;LOG10()&lt;/b&gt;, &lt;b&gt;밑이 2인 로그&lt;/b&gt;를 구하는 &lt;b&gt;LOG2()&lt;/b&gt;도 별도로 제공한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328707140&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LOG10(1000);   -- 결과: 3
SELECT LOG2(8);       -- 결과: 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1715&quot; data-start=&quot;1685&quot; data-ke-size=&quot;size16&quot;&gt;로그 스케일 변환, 이진 분할 계산 등에 자주 쓰인다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1739&quot; data-start=&quot;1717&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 로그 스케일 통계 처리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328715061&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LOG10(view_count) AS log_view
FROM video_stats;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1883&quot; data-start=&quot;1808&quot; data-ke-size=&quot;size16&quot;&gt;접속 수, 조회 수 등의 &lt;b&gt;큰 수치를 로그 스케일로 축소&lt;/b&gt;해 비교 분석할 수 있다. 그래프 축 정렬, 통계 정규화 등에 효과적이다.&lt;/p&gt;
&lt;h2 data-end=&quot;1915&quot; data-start=&quot;1885&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: EXP와 LOG를 조합한 역함수 예시&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328719694&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LOG(EXP(3)); -- 결과: 3
SELECT EXP(LOG(5)); -- 결과: 5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2038&quot; data-start=&quot;1987&quot; data-ke-size=&quot;size16&quot;&gt;EXP와 LOG는 서로 역관계이므로, 데이터를 변환한 뒤 다시 원래 값으로 복원할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;2045&quot; data-start=&quot;2040&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2315&quot; data-start=&quot;2047&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2094&quot; data-start=&quot;2047&quot;&gt;SQRT()는 제곱근을 구하며, 거리 계산이나 통계 분석에서 자주 쓰인다.&lt;/li&gt;
&lt;li data-end=&quot;2144&quot; data-start=&quot;2095&quot;&gt;EXP()는 e의 거듭제곱을 반환하며, 복리 계산, 성장률 모델에 필수적이다.&lt;/li&gt;
&lt;li data-end=&quot;2204&quot; data-start=&quot;2145&quot;&gt;LOG()는 자연 로그 함수이며, 로그 스케일 변환, 확률 처리, 지수 역함수 등에서 사용된다.&lt;/li&gt;
&lt;li data-end=&quot;2265&quot; data-start=&quot;2205&quot;&gt;LOG10(), LOG2()를 활용하면 밑이 10, 2인 로그 연산도 손쉽게 처리할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;2315&quot; data-start=&quot;2266&quot;&gt;이 함수들은 수학적 정확도뿐 아니라 &lt;b&gt;실제 데이터 해석에 매우 중요한 도구&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2325&quot; data-start=&quot;2317&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2574&quot; data-start=&quot;2327&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_sqrt&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_sqrt&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_exp&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_exp&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_log&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_log&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2651&quot; data-start=&quot;2592&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB수식정리</category>
      <category>exp</category>
      <category>log</category>
      <category>MYSQL</category>
      <category>MySQL수학함수</category>
      <category>SQL통계처리</category>
      <category>sqrt</category>
      <category>로그함수</category>
      <category>복리계산</category>
      <category>제곱근계산</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1071</guid>
      <comments>https://monkeybusiness.tistory.com/1071#entry1071comment</comments>
      <pubDate>Thu, 24 Jul 2025 20:45:54 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] MOD, DIV, %, POW로 나머지&amp;middot;제곱 계산하기</title>
      <link>https://monkeybusiness.tistory.com/1070</link>
      <description>&lt;p data-end=&quot;419&quot; data-start=&quot;219&quot; data-ke-size=&quot;size16&quot;&gt;숫자 연산 중에서도 &lt;b&gt;나머지 구하기&lt;/b&gt;와 &lt;b&gt;거듭제곱(제곱) 계산&lt;/b&gt;은 통계 분석, 페이지 분할, 짝수/홀수 판별, 수학 공식 구현 등 다양한 실무에서 자주 사용된다. MySQL에서는 이런 연산을 위한 함수로 &lt;b&gt;MOD()&lt;/b&gt;, &lt;b&gt;DIV&lt;/b&gt;, &lt;b&gt;% 연산자&lt;/b&gt;, &lt;b&gt;POW()&lt;/b&gt;를 제공한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gx8k0/btsPvsm1Bry/0rBy9ivQelqkVPkW1SVyW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gx8k0/btsPvsm1Bry/0rBy9ivQelqkVPkW1SVyW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gx8k0/btsPvsm1Bry/0rBy9ivQelqkVPkW1SVyW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGx8k0%2FbtsPvsm1Bry%2F0rBy9ivQelqkVPkW1SVyW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;534&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;442&quot; data-start=&quot;421&quot; data-ke-size=&quot;size26&quot;&gt;MOD() 함수 &amp;ndash; 나머지 구하기&lt;/h2&gt;
&lt;p data-end=&quot;496&quot; data-start=&quot;444&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MOD(a, b)&lt;/b&gt;는 a &amp;divide; b 연산의 &lt;b&gt;나머지(remainder)&lt;/b&gt;를 반환한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328406708&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT MOD(10, 3); -- 결과: 1
SELECT MOD(15, 5); -- 결과: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;600&quot; data-start=&quot;566&quot; data-ke-size=&quot;size16&quot;&gt;음수 입력도 지원하며 방향성은 첫 번째 인자에 영향을 받는다.&lt;/p&gt;
&lt;h3 data-end=&quot;618&quot; data-start=&quot;602&quot; data-ke-size=&quot;size23&quot;&gt;예제: 홀수/짝수 판별&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328414228&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT user_id,
       IF(MOD(user_id, 2) = 0, '짝수', '홀수') AS 구분
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;752&quot; data-start=&quot;709&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 MOD를 이용해 &lt;b&gt;번호, 순번, ID 등의 홀짝 분류&lt;/b&gt;가 가능하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;776&quot; data-start=&quot;754&quot; data-ke-size=&quot;size26&quot;&gt;% 연산자 &amp;ndash; MOD의 대체 연산자&lt;/h2&gt;
&lt;p data-end=&quot;856&quot; data-start=&quot;778&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 C언어 스타일의 &lt;b&gt;a % b&lt;/b&gt; 연산자도 사용할 수 있으며, 이는 &lt;b&gt;MOD(a, b)&lt;/b&gt;와 완전히 동일하게 동작한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328421196&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 10 % 3; -- 결과: 1
SELECT 15 % 5; -- 결과: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1030&quot; data-start=&quot;918&quot; data-ke-size=&quot;size16&quot;&gt;다만, &lt;b&gt;% 연산자는 SQL 표준 함수는 아니기 때문에 일부 DBMS에서는 사용 불가&lt;/b&gt;할 수 있다. MySQL에서는 사용 가능하지만, 가독성과 호환성을 위해 MOD()를 사용하는 것을 추천한다.&lt;/p&gt;
&lt;h2 data-end=&quot;1060&quot; data-start=&quot;1032&quot; data-ke-size=&quot;size26&quot;&gt;DIV 연산자 &amp;ndash; 몫(Quotient) 구하기&lt;/h2&gt;
&lt;p data-end=&quot;1127&quot; data-start=&quot;1062&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;a DIV b&lt;/b&gt;는 나눗셈 결과의 &lt;b&gt;정수 몫&lt;/b&gt;만 반환한다. FLOOR(a / b)와 동일한 효과를 가진다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328434150&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 10 DIV 3; -- 결과: 3
SELECT 15 DIV 5; -- 결과: 3
SELECT 7 DIV 2;  -- 결과: 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1254&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;DIV는 페이지 계산, 그룹 인덱싱, 묶음 처리 등에 유용하다.&lt;/p&gt;
&lt;h3 data-end=&quot;1283&quot; data-start=&quot;1256&quot; data-ke-size=&quot;size23&quot;&gt;예제: 10개씩 묶어서 페이지 번호 구하기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328439476&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT item_id,
       (item_id - 1) DIV 10 + 1 AS page_no
FROM items;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1399&quot; data-start=&quot;1368&quot; data-ke-size=&quot;size16&quot;&gt;페이지네이션, 인덱스 묶음 분할 처리에서 자주 활용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1422&quot; data-start=&quot;1401&quot; data-ke-size=&quot;size26&quot;&gt;POW() 함수 &amp;ndash; 거듭제곱 계산&lt;/h2&gt;
&lt;p data-end=&quot;1530&quot; data-start=&quot;1424&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;POW(base, exponent)&lt;/b&gt;는 &lt;b&gt;base의 exponent 제곱&lt;/b&gt; 값을 반환한다. &lt;b&gt;EXP(LOG(base) * exponent)&lt;/b&gt;와 같은 수학식과 동일한 결과를 준다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328463284&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT POW(2, 3); -- 결과: 8
SELECT POW(10, 2); -- 결과: 100&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1660&quot; data-start=&quot;1601&quot; data-ke-size=&quot;size16&quot;&gt;거듭제곱은 복리 계산, 그래프 좌표 계산, 확률 분포 처리 등 다양한 수학적 처리에서 필수적으로 사용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;1682&quot; data-start=&quot;1662&quot; data-ke-size=&quot;size23&quot;&gt;예제: 복리 계산 공식에 적용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328469669&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT principal * POW(1 + rate, periods) AS final_amount
FROM investment;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1838&quot; data-start=&quot;1771&quot; data-ke-size=&quot;size16&quot;&gt;이 쿼리는 투자 원금(principal), 이율(rate), 기간(periods)을 기준으로 복리 이자 계산을 수행한다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1865&quot; data-start=&quot;1840&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: ID 끝자리를 기준으로 분류&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328475572&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT user_id,
       MOD(user_id, 10) AS 마지막숫자
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1986&quot; data-start=&quot;1940&quot; data-ke-size=&quot;size16&quot;&gt;고객 ID 끝자리 기준으로 분류하거나, 로드 밸런싱 구간을 정할 때 자주 활용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;2002&quot; data-start=&quot;1988&quot; data-ke-size=&quot;size26&quot;&gt;MOD vs % 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2297&quot; data-start=&quot;2004&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;MOD(a, b)&lt;/td&gt;
&lt;td&gt;a % b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2158&quot; data-start=&quot;2112&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2123&quot; data-start=&quot;2112&quot;&gt;반환 값&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2140&quot; data-start=&quot;2123&quot;&gt;나머지&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2158&quot; data-start=&quot;2140&quot;&gt;나머지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2207&quot; data-start=&quot;2159&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2171&quot; data-start=&quot;2159&quot;&gt;SQL 표준&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2189&quot; data-start=&quot;2171&quot;&gt;예&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2207&quot; data-start=&quot;2189&quot;&gt;아님&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2254&quot; data-start=&quot;2208&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2220&quot; data-start=&quot;2208&quot;&gt;가독성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2238&quot; data-start=&quot;2220&quot;&gt;높음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2254&quot; data-start=&quot;2238&quot;&gt;낮을 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2297&quot; data-start=&quot;2255&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2266&quot; data-start=&quot;2255&quot;&gt;추천 방식&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2282&quot; data-start=&quot;2266&quot;&gt;✅ MOD() 사용 권장&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2297&quot; data-start=&quot;2282&quot;&gt;❌ 제한적 사용 추천&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2304&quot; data-start=&quot;2299&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2539&quot; data-start=&quot;2306&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2374&quot; data-start=&quot;2306&quot;&gt;MOD(a, b) 또는 a % b는 나머지를 계산하며, 조건 분류, 반복 처리, 홀짝 판별 등에 필수적이다.&lt;/li&gt;
&lt;li data-end=&quot;2425&quot; data-start=&quot;2375&quot;&gt;a DIV b는 정수 몫을 구할 때 쓰이며, 페이지 계산이나 인덱싱에 유용하다.&lt;/li&gt;
&lt;li data-end=&quot;2487&quot; data-start=&quot;2426&quot;&gt;POW(a, b)는 제곱 연산을 처리하며, 금융 계산, 좌표 변환 등 수학적 상황에 자주 사용된다.&lt;/li&gt;
&lt;li data-end=&quot;2539&quot; data-start=&quot;2488&quot;&gt;MOD와 DIV는 함께 쓰면 &lt;b&gt;분할과 구분을 정확히 처리할 수 있는 핵심 조합&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2549&quot; data-start=&quot;2541&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2795&quot; data-start=&quot;2551&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_mod&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_mod&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_div&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_div&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_pow&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_pow&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2875&quot; data-start=&quot;2813&quot; data-ke-size=&quot;size16&quot;&gt;#복리계산 #거듭제곱계산 #홀수짝수판별&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB계산예제</category>
      <category>div</category>
      <category>MOD</category>
      <category>MYSQL</category>
      <category>MySQL수학함수</category>
      <category>MySQL연산자</category>
      <category>pow</category>
      <category>SQL분류처리</category>
      <category>나머지계산</category>
      <category>제곱계산</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1070</guid>
      <comments>https://monkeybusiness.tistory.com/1070#entry1070comment</comments>
      <pubDate>Thu, 24 Jul 2025 19:42:51 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] ROUND, TRUNCATE로 소수점 제어하기</title>
      <link>https://monkeybusiness.tistory.com/1069</link>
      <description>&lt;p data-end=&quot;472&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;숫자를 다루는 모든 데이터 처리에서 &lt;b&gt;소수점 자릿수를 제어하는 작업&lt;/b&gt;은 꼭 필요하다. MySQL에서는 이런 작업을 위해 대표적으로 &lt;b&gt;ROUND()&lt;/b&gt;와 &lt;b&gt;TRUNCATE()&lt;/b&gt; 함수를 제공한다. 이 두 함수는 공통적으로 숫자의 소수점을 다루지만, &lt;b&gt;반올림(rounding)&lt;/b&gt;이냐 &lt;b&gt;버림(truncation)&lt;/b&gt;이냐에 따라 동작 방식이 완전히 다르다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgF5Do/btsPwyl5YS3/dzDvd1bVdZH8Fl7yerLFhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgF5Do/btsPwyl5YS3/dzDvd1bVdZH8Fl7yerLFhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgF5Do/btsPwyl5YS3/dzDvd1bVdZH8Fl7yerLFhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgF5Do%2FbtsPwyl5YS3%2FdzDvd1bVdZH8Fl7yerLFhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;496&quot; data-start=&quot;474&quot; data-ke-size=&quot;size26&quot;&gt;ROUND() 함수 &amp;ndash; 반올림 처리&lt;/h2&gt;
&lt;p data-end=&quot;568&quot; data-start=&quot;498&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ROUND(number, decimal_places)&lt;/b&gt; 함수는 지정한 소수점 자릿수까지 &lt;b&gt;반올림&lt;/b&gt;하여 값을 반환한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328257780&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ROUND(123.4567, 2); -- 결과: 123.46
SELECT ROUND(123.4567, 0); -- 결과: 123&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;700&quot; data-start=&quot;661&quot; data-ke-size=&quot;size16&quot;&gt;소수점 이하를 반올림하고, 두 번째 인자를 생략하면 정수로 반올림한다.&lt;/p&gt;
&lt;h3 data-end=&quot;720&quot; data-start=&quot;702&quot; data-ke-size=&quot;size23&quot;&gt;예제: 가격 소수점 반올림&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328265012&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT product_id, price, ROUND(price, 1) AS round_price
FROM products;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;856&quot; data-start=&quot;806&quot; data-ke-size=&quot;size16&quot;&gt;1원 단위까지 반올림해 가격을 표시할 수 있다. 전자상거래, 송금 시스템 등에서 사용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;878&quot; data-start=&quot;858&quot; data-ke-size=&quot;size23&quot;&gt;예제: 반올림하여 백단위 처리&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328270132&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ROUND(amount, -2) AS 백단위반올림
FROM payments;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1034&quot; data-start=&quot;942&quot; data-ke-size=&quot;size16&quot;&gt;소수점 아래가 아닌 &lt;b&gt;정수 자릿수에서 반올림&lt;/b&gt;하려면 음수 값을 두 번째 인자로 사용한다. 이 기능은 &lt;b&gt;백단위 결제&lt;/b&gt;, &lt;b&gt;천단위 세금 계산&lt;/b&gt; 등에 유용하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1060&quot; data-start=&quot;1036&quot; data-ke-size=&quot;size26&quot;&gt;TRUNCATE() 함수 &amp;ndash; 버림 처리&lt;/h2&gt;
&lt;p data-end=&quot;1147&quot; data-start=&quot;1062&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TRUNCATE(number, decimal_places)&lt;/b&gt; 함수는 소수점 아래를 &lt;b&gt;버림(truncate)&lt;/b&gt; 처리하여 해당 자릿수까지만 남긴다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328277972&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TRUNCATE(123.4567, 2); -- 결과: 123.45
SELECT TRUNCATE(123.4567, 0); -- 결과: 123&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1285&quot; data-start=&quot;1246&quot; data-ke-size=&quot;size16&quot;&gt;반올림 없이 단순히 해당 자릿수까지 &lt;b&gt;잘라내는 방식&lt;/b&gt;으로 처리된다.&lt;/p&gt;
&lt;h3 data-end=&quot;1301&quot; data-start=&quot;1287&quot; data-ke-size=&quot;size23&quot;&gt;예제: 포인트 절사&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328283460&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TRUNCATE(value, 4) AS 정확도값
FROM lab_results;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1445&quot; data-start=&quot;1384&quot; data-ke-size=&quot;size16&quot;&gt;정수 단위까지만 남기고 소수점은 절사 처리한다. &lt;b&gt;포인트 절사, 할인율 계산, 통계 요약&lt;/b&gt; 등에 사용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;1468&quot; data-start=&quot;1447&quot; data-ke-size=&quot;size23&quot;&gt;예제: 소수 넷째자리까지만 유지&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328290788&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TRUNCATE(value, 4) AS 정확도값
FROM lab_results;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1580&quot; data-start=&quot;1534&quot; data-ke-size=&quot;size16&quot;&gt;정밀한 수치를 표시할 때 사용되며, &lt;b&gt;금융, 과학, 계측 시스템에서 유용&lt;/b&gt;하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1608&quot; data-start=&quot;1582&quot; data-ke-size=&quot;size26&quot;&gt;ROUND vs TRUNCATE 비교 정리&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1967&quot; data-start=&quot;1610&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;ROUND()&lt;/td&gt;
&lt;td&gt;TRUNCATE()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1809&quot; data-start=&quot;1748&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1761&quot; data-start=&quot;1748&quot;&gt;기능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1785&quot; data-start=&quot;1761&quot;&gt;반올림&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1809&quot; data-start=&quot;1785&quot;&gt;버림 (절사)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1857&quot; data-start=&quot;1810&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1820&quot; data-start=&quot;1810&quot;&gt;음수 자리수&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1837&quot; data-start=&quot;1820&quot;&gt;지원 (정수 자리 반올림)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1857&quot; data-start=&quot;1837&quot;&gt;지원 (정수 자리 버림)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1906&quot; data-start=&quot;1858&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1869&quot; data-start=&quot;1858&quot;&gt;금융 정산&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1887&quot; data-start=&quot;1869&quot;&gt;부가세, 이자, 정산에 활용&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1906&quot; data-start=&quot;1887&quot;&gt;할인율, 포인트, 단가 절사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1967&quot; data-start=&quot;1907&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1918&quot; data-start=&quot;1907&quot;&gt;반환 타입&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1942&quot; data-start=&quot;1918&quot;&gt;DOUBLE 또는 DECIMAL&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1967&quot; data-start=&quot;1942&quot;&gt;DECIMAL 또는 DOUBLE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2014&quot; data-start=&quot;1969&quot; data-ke-size=&quot;size16&quot;&gt;둘 다 자릿수 제한은 가능하지만, &lt;b&gt;어떤 방식으로 처리되는지가 핵심 차이&lt;/b&gt;다.&lt;/p&gt;
&lt;h2 data-end=&quot;2031&quot; data-start=&quot;2016&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 환율 처리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328310340&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT currency,
       ROUND(exchange_rate, 2) AS round_rate,
       TRUNCATE(exchange_rate, 2) AS cut_rate
FROM forex;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2230&quot; data-start=&quot;2166&quot; data-ke-size=&quot;size16&quot;&gt;표시는 반올림된 값을 사용하고, &lt;b&gt;정산이나 내부 계산은 절사된 값을 사용하는 방식&lt;/b&gt;으로 같이 쓰는 경우가 많다.&lt;/p&gt;
&lt;h2 data-end=&quot;2237&quot; data-start=&quot;2232&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2482&quot; data-start=&quot;2239&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2296&quot; data-start=&quot;2239&quot;&gt;ROUND()는 반올림 함수로 소수점 자릿수 지정이 가능하며, 정수 자리도 반올림 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;2349&quot; data-start=&quot;2297&quot;&gt;TRUNCATE()는 버림 함수로 단순히 자릿수를 잘라내며, 반올림은 하지 않는다.&lt;/li&gt;
&lt;li data-end=&quot;2432&quot; data-start=&quot;2350&quot;&gt;두 함수 모두 정수와 실수 데이터를 처리할 수 있으며, 실무에서는 &lt;b&gt;함수의 의도를 명확히 이해하고 상황에 맞게 선택&lt;/b&gt;하는 것이 중요하다.&lt;/li&gt;
&lt;li data-end=&quot;2482&quot; data-start=&quot;2433&quot;&gt;금액 처리, 포인트 절사, 리포트 정리 등 다양한 분야에서 이 두 함수는 필수적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2492&quot; data-start=&quot;2484&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2664&quot; data-start=&quot;2494&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_round&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_round&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_truncate&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_truncate&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2751&quot; data-start=&quot;2682&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB금액계산</category>
      <category>MYSQL</category>
      <category>MySQL수학함수</category>
      <category>MySQL예제정리</category>
      <category>round</category>
      <category>SQL소수점제어</category>
      <category>truncate</category>
      <category>반올림</category>
      <category>소수점처리</category>
      <category>절사</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1069</guid>
      <comments>https://monkeybusiness.tistory.com/1069#entry1069comment</comments>
      <pubDate>Thu, 24 Jul 2025 18:38:54 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] IF vs CASE 차이점과 선택 기준 정리</title>
      <link>https://monkeybusiness.tistory.com/1080</link>
      <description>&lt;p data-end=&quot;335&quot; data-start=&quot;206&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 조건 분기를 처리할 때 가장 많이 사용하는 두 가지 흐름 제어 함수는 &lt;b&gt;IF()&lt;/b&gt;와 &lt;b&gt;CASE WHEN&lt;/b&gt;이다. 둘 다 조건에 따라 다른 값을 반환하지만, &lt;b&gt;표현 방식과 사용 목적에는 분명한 차이점&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFcuo2/btsPxWtFsBS/IZ0eIiojPlqfKFuLksVMrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFcuo2/btsPxWtFsBS/IZ0eIiojPlqfKFuLksVMrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFcuo2/btsPxWtFsBS/IZ0eIiojPlqfKFuLksVMrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFcuo2%2FbtsPxWtFsBS%2FIZ0eIiojPlqfKFuLksVMrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;453&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;450&quot; data-start=&quot;438&quot; data-ke-size=&quot;size26&quot;&gt;IF 함수의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;526&quot; data-start=&quot;452&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;476&quot; data-start=&quot;452&quot;&gt;&lt;b&gt;간단한 조건 분기 처리&lt;/b&gt;에 적합&lt;/li&gt;
&lt;li data-end=&quot;499&quot; data-start=&quot;477&quot;&gt;조건 ? 참값 : 거짓값 구조&lt;/li&gt;
&lt;li data-end=&quot;526&quot; data-start=&quot;500&quot;&gt;&lt;b&gt;중첩 IF는 복잡하고 가독성이 떨어짐&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346765857&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT name, score,
       IF(score &amp;gt;= 60, '합격', '불합격') AS 결과
FROM exam_result;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;651&quot; data-start=&quot;620&quot; data-ke-size=&quot;size16&quot;&gt;2개의 조건만 비교할 때 가장 깔끔하게 사용할 수 있다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;667&quot; data-start=&quot;653&quot; data-ke-size=&quot;size26&quot;&gt;CASE 함수의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;771&quot; data-start=&quot;669&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;689&quot; data-start=&quot;669&quot;&gt;&lt;b&gt;다중 조건 분기&lt;/b&gt;에 적합&lt;/li&gt;
&lt;li data-end=&quot;734&quot; data-start=&quot;690&quot;&gt;WHEN 절을 여러 개 사용할 수 있어 &lt;b&gt;복잡한 분류 처리에 강력함&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;771&quot; data-start=&quot;735&quot;&gt;CASE WHEN ~ THEN ~ ELSE ~ END 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346774065&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT name, score,
       CASE
         WHEN score &amp;gt;= 90 THEN 'A'
         WHEN score &amp;gt;= 80 THEN 'B'
         WHEN score &amp;gt;= 70 THEN 'C'
         ELSE 'F'
       END AS 등급
FROM students;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1004&quot; data-start=&quot;972&quot; data-ke-size=&quot;size16&quot;&gt;조건이 많을수록 CASE가 훨씬 깔끔하고 유지보수도 쉽다.&lt;/p&gt;
&lt;h2 data-end=&quot;1023&quot; data-start=&quot;1006&quot; data-ke-size=&quot;size26&quot;&gt;IF vs CASE 비교표&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1813&quot; data-start=&quot;1025&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;IF 함수&lt;/td&gt;
&lt;td&gt;CASE WHEN 문&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1307&quot; data-start=&quot;1222&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1237&quot; data-start=&quot;1222&quot;&gt;조건 수&lt;/td&gt;
&lt;td data-end=&quot;1267&quot; data-start=&quot;1237&quot; data-col-size=&quot;sm&quot;&gt;2개 (참/거짓)&lt;/td&gt;
&lt;td data-end=&quot;1307&quot; data-start=&quot;1267&quot; data-col-size=&quot;sm&quot;&gt;다중 조건 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1386&quot; data-start=&quot;1308&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1323&quot; data-start=&quot;1308&quot;&gt;가독성&lt;/td&gt;
&lt;td data-end=&quot;1348&quot; data-start=&quot;1323&quot; data-col-size=&quot;sm&quot;&gt;간단하지만 중첩 시 난해&lt;/td&gt;
&lt;td data-end=&quot;1386&quot; data-start=&quot;1348&quot; data-col-size=&quot;sm&quot;&gt;구조적이고 명확함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1462&quot; data-start=&quot;1387&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1402&quot; data-start=&quot;1387&quot;&gt;사용 예&lt;/td&gt;
&lt;td data-end=&quot;1431&quot; data-start=&quot;1402&quot; data-col-size=&quot;sm&quot;&gt;합격 여부, NULL 처리&lt;/td&gt;
&lt;td data-end=&quot;1462&quot; data-start=&quot;1431&quot; data-col-size=&quot;sm&quot;&gt;등급 분류, 정렬 순서, 복잡한 조건 분기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1557&quot; data-start=&quot;1463&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1479&quot; data-start=&quot;1463&quot;&gt;SELECT 사용&lt;/td&gt;
&lt;td data-end=&quot;1512&quot; data-start=&quot;1479&quot; data-col-size=&quot;sm&quot;&gt;가능&lt;/td&gt;
&lt;td data-end=&quot;1557&quot; data-start=&quot;1512&quot; data-col-size=&quot;sm&quot;&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1654&quot; data-start=&quot;1558&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1576&quot; data-start=&quot;1558&quot;&gt;WHERE, ORDER BY&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1609&quot; data-start=&quot;1576&quot;&gt;가능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1654&quot; data-start=&quot;1609&quot;&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1731&quot; data-start=&quot;1655&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1669&quot; data-start=&quot;1655&quot;&gt;중첩 사용&lt;/td&gt;
&lt;td data-end=&quot;1695&quot; data-start=&quot;1669&quot; data-col-size=&quot;sm&quot;&gt;가능하지만 복잡해짐&lt;/td&gt;
&lt;td data-end=&quot;1731&quot; data-start=&quot;1695&quot; data-col-size=&quot;sm&quot;&gt;구조적으로 중첩에 강함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1813&quot; data-start=&quot;1732&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1746&quot; data-start=&quot;1732&quot;&gt;성능 차이&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1777&quot; data-start=&quot;1746&quot;&gt;거의 없음&lt;/td&gt;
&lt;td data-end=&quot;1813&quot; data-start=&quot;1777&quot; data-col-size=&quot;sm&quot;&gt;조건 수 많아도 최적화됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1826&quot; data-start=&quot;1815&quot; data-ke-size=&quot;size26&quot;&gt;실무 선택 기준&lt;/h2&gt;
&lt;p data-end=&quot;1882&quot; data-start=&quot;1828&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;조건이 단 하나 또는 최대 2개일 경우&lt;/b&gt;&lt;br /&gt;&amp;rarr; IF() 사용이 간결하고 효율적이다.&lt;/p&gt;
&lt;p data-end=&quot;1938&quot; data-start=&quot;1884&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;조건이 3개 이상일 경우&lt;/b&gt;&lt;br /&gt;&amp;rarr; CASE를 사용하면 가독성과 유지보수가 훨씬 좋다.&lt;/p&gt;
&lt;p data-end=&quot;2005&quot; data-start=&quot;1940&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;정렬 순서를 직접 제어하거나 등급처럼 다양한 조건별 분기를 할 경우&lt;/b&gt;&lt;br /&gt;&amp;rarr; CASE가 유일한 선택이다.&lt;/p&gt;
&lt;h2 data-end=&quot;2017&quot; data-start=&quot;2007&quot; data-ke-size=&quot;size26&quot;&gt;성능 측면은?&lt;/h2&gt;
&lt;p data-end=&quot;2124&quot; data-start=&quot;2019&quot; data-ke-size=&quot;size16&quot;&gt;IF()와 CASE 모두 MySQL 내부에서 최적화가 잘 되어 있기 때문에 &lt;b&gt;실행 성능 차이는 거의 없다&lt;/b&gt;. 성능보다는 &lt;b&gt;가독성과 유지보수성&lt;/b&gt;을 기준으로 선택하는 것이 좋다.&lt;/p&gt;
&lt;h2 data-end=&quot;2149&quot; data-start=&quot;2126&quot; data-ke-size=&quot;size26&quot;&gt;예제: 중첩 IF vs CASE 비교&lt;/h2&gt;
&lt;h3 data-end=&quot;2160&quot; data-start=&quot;2151&quot; data-ke-size=&quot;size23&quot;&gt;중첩 IF&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346797921&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IF(score &amp;gt;= 90, 'A',
   IF(score &amp;gt;= 80, 'B',
      IF(score &amp;gt;= 70, 'C', 'F')))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2265&quot; data-start=&quot;2253&quot; data-ke-size=&quot;size23&quot;&gt;동일한 CASE&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753346805153&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CASE
  WHEN score &amp;gt;= 90 THEN 'A'
  WHEN score &amp;gt;= 80 THEN 'B'
  WHEN score &amp;gt;= 70 THEN 'C'
  ELSE 'F'
END&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2408&quot; data-start=&quot;2383&quot; data-ke-size=&quot;size16&quot;&gt;복잡도가 높아질수록 CASE가 훨씬 유리하다.&lt;/p&gt;
&lt;h2 data-end=&quot;2415&quot; data-start=&quot;2410&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2591&quot; data-start=&quot;2417&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2467&quot; data-start=&quot;2417&quot;&gt;IF()는 단순한 조건 분기, CASE는 복잡한 다중 조건 분기에 적합하다.&lt;/li&gt;
&lt;li data-end=&quot;2512&quot; data-start=&quot;2468&quot;&gt;성능 차이는 거의 없지만 가독성과 유지보수성 측면에서 큰 차이를 보인다.&lt;/li&gt;
&lt;li data-end=&quot;2549&quot; data-start=&quot;2513&quot;&gt;실무에서는 조건 개수에 따라 적절한 함수 선택이 중요하다.&lt;/li&gt;
&lt;li data-end=&quot;2591&quot; data-start=&quot;2550&quot;&gt;&lt;b&gt;조건이 3개 이상이면 무조건 CASE를 사용하는 것을 권장&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2601&quot; data-start=&quot;2593&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2670&quot; data-start=&quot;2603&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2764&quot; data-start=&quot;2688&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>CASEWHEN사용법</category>
      <category>IFvsCASE</category>
      <category>IF문활용</category>
      <category>MYSQL</category>
      <category>mysql실무팁</category>
      <category>SQL조건문</category>
      <category>SQL조건비교</category>
      <category>다중조건처리</category>
      <category>쿼리가독성</category>
      <category>흐름제어함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1080</guid>
      <comments>https://monkeybusiness.tistory.com/1080#entry1080comment</comments>
      <pubDate>Thu, 24 Jul 2025 17:49:04 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] ABS, CEIL, FLOOR로 절댓값과 반올림 처리하기</title>
      <link>https://monkeybusiness.tistory.com/1068</link>
      <description>&lt;p data-end=&quot;426&quot; data-start=&quot;219&quot; data-ke-size=&quot;size16&quot;&gt;숫자 데이터를 다룰 때 가장 기본이면서도 자주 쓰이는 기능이 바로 &lt;b&gt;절댓값&lt;/b&gt;, &lt;b&gt;올림&lt;/b&gt;, &lt;b&gt;버림&lt;/b&gt;이다. MySQL에서는 이를 위한 대표적인 수학 함수로 &lt;b&gt;ABS()&lt;/b&gt;, &lt;b&gt;CEIL()&lt;/b&gt;, &lt;b&gt;FLOOR()&lt;/b&gt;를 제공한다. 이 함수들은 실무에서 &lt;b&gt;정규화, 통계 처리, 금액 정리, 소수점 제어&lt;/b&gt;에 매우 자주 사용되며, 다양한 실전 시나리오에서 활용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y27QV/btsPv2BoofF/NwSurByUWa4NkFwkDYOig0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y27QV/btsPv2BoofF/NwSurByUWa4NkFwkDYOig0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y27QV/btsPv2BoofF/NwSurByUWa4NkFwkDYOig0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY27QV%2FbtsPv2BoofF%2FNwSurByUWa4NkFwkDYOig0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;540&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;450&quot; data-start=&quot;428&quot; data-ke-size=&quot;size26&quot;&gt;ABS() 함수 &amp;ndash; 절댓값 반환하기&lt;/h2&gt;
&lt;p data-end=&quot;540&quot; data-start=&quot;452&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ABS(number)&lt;/b&gt; 함수는 주어진 &lt;b&gt;숫자의 절댓값(absolute value)&lt;/b&gt;을 반환한다. 즉, 음수이면 양수로 바뀌고 양수는 그대로 유지된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328123279&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ABS(-100); -- 결과: 100
SELECT ABS(25);   -- 결과: 25&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;668&quot; data-start=&quot;611&quot; data-ke-size=&quot;size16&quot;&gt;이 함수는 보통 &lt;b&gt;수익 손실 계산&lt;/b&gt;, &lt;b&gt;변동폭 분석&lt;/b&gt;, &lt;b&gt;절댓값 기준 비교&lt;/b&gt; 등에 활용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;690&quot; data-start=&quot;670&quot; data-ke-size=&quot;size23&quot;&gt;예제: 수익 손실 절댓값 보기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328128788&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT order_id, profit, ABS(profit) AS absolute_profit
FROM sales;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;820&quot; data-start=&quot;772&quot; data-ke-size=&quot;size16&quot;&gt;음수인 손실도 양수로 보여주면서 &lt;b&gt;정렬이나 비교에 유리한 형태&lt;/b&gt;로 가공할 수 있다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;843&quot; data-start=&quot;822&quot; data-ke-size=&quot;size26&quot;&gt;CEIL() 함수 &amp;ndash; 소수점 올림&lt;/h2&gt;
&lt;p data-end=&quot;955&quot; data-start=&quot;845&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CEIL(number)&lt;/b&gt; 또는 &lt;b&gt;CEILING(number)&lt;/b&gt; 함수는 주어진 수보다 &lt;b&gt;크거나 같은 최소 정수&lt;/b&gt;를 반환한다. 즉, 소수점 이하가 조금이라도 있다면 &lt;b&gt;무조건 올림&lt;/b&gt;한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328136116&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CEIL(10.2);   -- 결과: 11
SELECT CEIL(-5.7);   -- 결과: -5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1047&quot; data-start=&quot;1031&quot; data-ke-size=&quot;size23&quot;&gt;예제: 페이지 수 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328141284&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CEIL(total_items / 10) AS total_pages
FROM item_summary;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1197&quot; data-start=&quot;1125&quot; data-ke-size=&quot;size16&quot;&gt;전체 항목 수를 10개씩 나눠 보여줄 때, 소수점이 발생해도 &lt;b&gt;무조건 다음 페이지를 만들어야 하므로 CEIL이 꼭 필요&lt;/b&gt;하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1221&quot; data-start=&quot;1199&quot; data-ke-size=&quot;size26&quot;&gt;FLOOR() 함수 &amp;ndash; 소수점 버림&lt;/h2&gt;
&lt;p data-end=&quot;1301&quot; data-start=&quot;1223&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FLOOR(number)&lt;/b&gt; 함수는 주어진 수보다 &lt;b&gt;작거나 같은 최대 정수&lt;/b&gt;를 반환한다. 즉, 소수점 이하는 &lt;b&gt;무조건 버림&lt;/b&gt;한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328150101&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FLOOR(10.9);  -- 결과: 10
SELECT FLOOR(-5.1);  -- 결과: -6&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1434&quot; data-start=&quot;1377&quot; data-ke-size=&quot;size16&quot;&gt;CEIL과 반대 방향으로 작동하며, &lt;b&gt;금액 절사&lt;/b&gt;, &lt;b&gt;범위 내 위치 지정&lt;/b&gt; 등에 자주 사용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;1452&quot; data-start=&quot;1436&quot; data-ke-size=&quot;size23&quot;&gt;예제: 등급 구간 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328156020&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FLOOR(score / 10) AS 등급
FROM test_result;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1550&quot; data-start=&quot;1515&quot; data-ke-size=&quot;size16&quot;&gt;점수를 10점 단위로 끊어서 등급을 매기는 데 활용할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1571&quot; data-start=&quot;1552&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 반올림 금액 처리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753328163027&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT product_name,
       price,
       CEIL(price / 100) * 100 AS round_up_price,
       FLOOR(price / 100) * 100 AS round_down_price
FROM products;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1800&quot; data-start=&quot;1737&quot; data-ke-size=&quot;size16&quot;&gt;단가를 100원 단위로 올림/버림하여 &lt;b&gt;결제 금액 조정&lt;/b&gt;이나 &lt;b&gt;이벤트 할인 조건 처리&lt;/b&gt; 등에 쓸 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1807&quot; data-start=&quot;1802&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2018&quot; data-start=&quot;1809&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1857&quot; data-start=&quot;1809&quot;&gt;&lt;b&gt;ABS()&lt;/b&gt;는 절댓값을 구하며, 주로 차이값 비교나 손익 계산에 사용된다.&lt;/li&gt;
&lt;li data-end=&quot;1914&quot; data-start=&quot;1858&quot;&gt;&lt;b&gt;CEIL()&lt;/b&gt;는 소수점이 있으면 무조건 올림하며, 페이지 처리나 라운딩 계산에 적합하다.&lt;/li&gt;
&lt;li data-end=&quot;1976&quot; data-start=&quot;1915&quot;&gt;&lt;b&gt;FLOOR()&lt;/b&gt;는 소수점을 무시하고 아래로 내림 처리하며, 금액 절사나 등급 분류에 자주 쓰인다.&lt;/li&gt;
&lt;li data-end=&quot;2018&quot; data-start=&quot;1977&quot;&gt;세 함수 모두 실무에서 매우 빈번하게 쓰이며, 다양한 응용이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2028&quot; data-start=&quot;2020&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;2097&quot; data-start=&quot;2030&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;2175&quot; data-start=&quot;2115&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>abs</category>
      <category>ceil</category>
      <category>Floor</category>
      <category>MYSQL</category>
      <category>MySQL수학함수</category>
      <category>mysql실무팁</category>
      <category>SQL라운딩</category>
      <category>반올림</category>
      <category>소수점처리</category>
      <category>절댓값</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1068</guid>
      <comments>https://monkeybusiness.tistory.com/1068#entry1068comment</comments>
      <pubDate>Thu, 24 Jul 2025 17:36:37 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] 실무에서 자주 겪는 성능 이슈와 해결법</title>
      <link>https://monkeybusiness.tistory.com/1067</link>
      <description>&lt;p data-end=&quot;426&quot; data-start=&quot;194&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 확장성과 유연성에서 강력한 이점을 제공하지만, 반대로 &lt;b&gt;운영 환경에서는 예기치 못한 성능 문제를 자주 유발&lt;/b&gt;한다.&lt;br /&gt;하나의 기능이 여러 서비스를 거쳐 동작하기 때문에 병목이 어디서 발생하는지 파악하기 어렵고, 특정 서비스 하나의 이상이 전체 장애로 이어지는 경우도 많다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by8Zu9/btsPwKNkHu6/au2z2EMhVjsTkmYSy34Vyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by8Zu9/btsPwKNkHu6/au2z2EMhVjsTkmYSy34Vyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by8Zu9/btsPwKNkHu6/au2z2EMhVjsTkmYSy34Vyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby8Zu9%2FbtsPwKNkHu6%2Fau2z2EMhVjsTkmYSy34Vyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;445&quot; data-start=&quot;428&quot; data-ke-size=&quot;size26&quot;&gt;✅ 성능 이슈의 근본 원인&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;618&quot; data-start=&quot;447&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;471&quot; data-start=&quot;447&quot;&gt;서비스 간 &lt;b&gt;네트워크 통신 증가&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;489&quot; data-start=&quot;472&quot;&gt;&lt;b&gt;N+1 호출 문제&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;520&quot; data-start=&quot;490&quot;&gt;&lt;b&gt;불필요한 데이터 로딩 또는 과다 페이로드&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;551&quot; data-start=&quot;521&quot;&gt;서비스 간 &lt;b&gt;의존도 증가로 인한 장애 전파&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;577&quot; data-start=&quot;552&quot;&gt;트랜잭션 처리의 &lt;b&gt;비효율적인 설계&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;595&quot; data-start=&quot;578&quot;&gt;&lt;b&gt;미비한 캐시 전략&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;618&quot; data-start=&quot;596&quot;&gt;분산 환경에서의 &lt;b&gt;모니터링 부족&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;645&quot; data-start=&quot;620&quot; data-ke-size=&quot;size26&quot;&gt;  대표 성능 이슈 7가지와 해결 전략&lt;/h2&gt;
&lt;h3 data-end=&quot;665&quot; data-start=&quot;647&quot; data-ke-size=&quot;size23&quot;&gt;1. 서비스 간 호출 지연&lt;/h3&gt;
&lt;p data-end=&quot;748&quot; data-start=&quot;667&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;서비스 간 HTTP 호출이 많아질수록 전체 응답 시간이 지연된다. 특히 체인 형태로 호출이 이어질 경우 병목 발생 가능성이 높다.&lt;/p&gt;
&lt;p data-end=&quot;759&quot; data-start=&quot;750&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;869&quot; data-start=&quot;760&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;785&quot; data-start=&quot;760&quot;&gt;WebClient &amp;rarr; 비동기 호출 적용&lt;/li&gt;
&lt;li data-end=&quot;812&quot; data-start=&quot;786&quot;&gt;응답 데이터 최소화 (DTO 필드 축소)&lt;/li&gt;
&lt;li data-end=&quot;838&quot; data-start=&quot;813&quot;&gt;호출 병렬화 또는 BFF에서 통합 처리&lt;/li&gt;
&lt;li data-end=&quot;869&quot; data-start=&quot;839&quot;&gt;&lt;b&gt;Bulk API&lt;/b&gt; 구성하여 한 번에 요청 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;892&quot; data-start=&quot;876&quot; data-ke-size=&quot;size23&quot;&gt;2. N+1 호출 문제&lt;/h3&gt;
&lt;p data-end=&quot;955&quot; data-start=&quot;894&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;A 서비스가 B 서비스에 대해 다수의 데이터를 순차 호출하는 구조에서 N+1 문제가 발생한다.&lt;/p&gt;
&lt;p data-end=&quot;966&quot; data-start=&quot;957&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1036&quot; data-start=&quot;967&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;996&quot; data-start=&quot;967&quot;&gt;요청 수 줄이기: List 단위로 한번에 호출&lt;/li&gt;
&lt;li data-end=&quot;1020&quot; data-start=&quot;997&quot;&gt;B 서비스에 배치 응답 API 구성&lt;/li&gt;
&lt;li data-end=&quot;1036&quot; data-start=&quot;1021&quot;&gt;데이터를 캐싱하여 재사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1061&quot; data-start=&quot;1043&quot; data-ke-size=&quot;size23&quot;&gt;3. 불필요한 데이터 응답&lt;/h3&gt;
&lt;p data-end=&quot;1129&quot; data-start=&quot;1063&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;모든 필드를 포함한 JSON 응답을 전달하면 네트워크 비용이 증가하고 클라이언트 처리 시간도 길어진다.&lt;/p&gt;
&lt;p data-end=&quot;1140&quot; data-start=&quot;1131&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1209&quot; data-start=&quot;1141&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1164&quot; data-start=&quot;1141&quot;&gt;DTO 설계 시 필요한 필드만 포함&lt;/li&gt;
&lt;li data-end=&quot;1193&quot; data-start=&quot;1165&quot;&gt;GraphQL 도입하여 필요한 데이터만 요청&lt;/li&gt;
&lt;li data-end=&quot;1209&quot; data-start=&quot;1194&quot;&gt;GZIP 압축 전송 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1243&quot; data-start=&quot;1216&quot; data-ke-size=&quot;size23&quot;&gt;4. 장애 전파로 인한 전체 시스템 느려짐&lt;/h3&gt;
&lt;p data-end=&quot;1293&quot; data-start=&quot;1245&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;하나의 서비스가 느려지거나 다운되면 전체 서비스 호출 체인이 지연된다.&lt;/p&gt;
&lt;p data-end=&quot;1304&quot; data-start=&quot;1295&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1390&quot; data-start=&quot;1305&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1344&quot; data-start=&quot;1305&quot;&gt;Circuit Breaker 적용 (Resilience4j 등)&lt;/li&gt;
&lt;li data-end=&quot;1363&quot; data-start=&quot;1345&quot;&gt;Fallback 로직 구현&lt;/li&gt;
&lt;li data-end=&quot;1390&quot; data-start=&quot;1364&quot;&gt;호출 Timeout 및 Retry 정책 명시&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1416&quot; data-start=&quot;1397&quot; data-ke-size=&quot;size23&quot;&gt;5. 데이터베이스 쿼리 병목&lt;/h3&gt;
&lt;p data-end=&quot;1471&quot; data-start=&quot;1418&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;서비스 자체는 빠르게 응답하지만 DB 쿼리가 느려서 전체 응답 시간이 지연된다.&lt;/p&gt;
&lt;p data-end=&quot;1482&quot; data-start=&quot;1473&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1588&quot; data-start=&quot;1483&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1500&quot; data-start=&quot;1483&quot;&gt;쿼리 튜닝, 인덱스 적용&lt;/li&gt;
&lt;li data-end=&quot;1530&quot; data-start=&quot;1501&quot;&gt;읽기 전용 쿼리는 Read Replica 사용&lt;/li&gt;
&lt;li data-end=&quot;1559&quot; data-start=&quot;1531&quot;&gt;데이터 캐시 (Redis, Caffeine)&lt;/li&gt;
&lt;li data-end=&quot;1588&quot; data-start=&quot;1560&quot;&gt;비정형 데이터는 Elasticsearch로 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1619&quot; data-start=&quot;1595&quot; data-ke-size=&quot;size23&quot;&gt;6. 캐시 미활용으로 인한 반복 호출&lt;/h3&gt;
&lt;p data-end=&quot;1672&quot; data-start=&quot;1621&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;매 요청마다 동일한 데이터를 조회하면 불필요한 연산과 DB 부하가 발생한다.&lt;/p&gt;
&lt;p data-end=&quot;1683&quot; data-start=&quot;1674&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1738&quot; data-start=&quot;1684&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1699&quot; data-start=&quot;1684&quot;&gt;Redis 기반 캐싱&lt;/li&gt;
&lt;li data-end=&quot;1719&quot; data-start=&quot;1700&quot;&gt;Spring Cache 사용&lt;/li&gt;
&lt;li data-end=&quot;1738&quot; data-start=&quot;1720&quot;&gt;프론트엔드에서 캐시 헤더 조절&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1770&quot; data-start=&quot;1745&quot; data-ke-size=&quot;size23&quot;&gt;7. 모니터링 부족으로 원인 추적 실패&lt;/h3&gt;
&lt;p data-end=&quot;1833&quot; data-start=&quot;1772&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;성능 이슈가 발생했지만 로그 외에 확인할 수 있는 지표나 시각화 도구가 없어 대응이 늦어진다.&lt;/p&gt;
&lt;p data-end=&quot;1844&quot; data-start=&quot;1835&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1974&quot; data-start=&quot;1845&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1872&quot; data-start=&quot;1845&quot;&gt;Prometheus + Grafana 도입&lt;/li&gt;
&lt;li data-end=&quot;1913&quot; data-start=&quot;1873&quot;&gt;Spring Boot Actuator + Micrometer 연동&lt;/li&gt;
&lt;li data-end=&quot;1944&quot; data-start=&quot;1914&quot;&gt;Sleuth + Zipkin으로 요청 추적 구성&lt;/li&gt;
&lt;li data-end=&quot;1974&quot; data-start=&quot;1945&quot;&gt;로그 집계(ELK/EFK) 기반 트러블슈팅 자동화&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1999&quot; data-start=&quot;1976&quot; data-ke-size=&quot;size26&quot;&gt; ️ 성능 안정화를 위한 추가 전략&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2246&quot; data-start=&quot;2001&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;전략&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2076&quot; data-start=&quot;2029&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2051&quot; data-start=&quot;2029&quot;&gt;API Gateway에서 응답 압축&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2076&quot; data-start=&quot;2051&quot;&gt;응답 페이로드 줄여 네트워크 병목 완화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2117&quot; data-start=&quot;2077&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2097&quot; data-start=&quot;2077&quot;&gt;Database Sharding&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2117&quot; data-start=&quot;2097&quot;&gt;트래픽 분산 및 스케일링 확보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2156&quot; data-start=&quot;2118&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2127&quot; data-start=&quot;2118&quot;&gt;BFF 분리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2156&quot; data-start=&quot;2127&quot;&gt;클라이언트 특화 응답 처리로 과도한 통신 방지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2200&quot; data-start=&quot;2157&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2170&quot; data-start=&quot;2157&quot;&gt;비동기 메시징 도입&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2200&quot; data-start=&quot;2170&quot;&gt;Kafka, RabbitMQ로 비핵심 작업 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2246&quot; data-start=&quot;2201&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2221&quot; data-start=&quot;2201&quot;&gt;Graceful Shutdown&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2246&quot; data-start=&quot;2221&quot;&gt;롤링 배포 중 사용자 요청 안전하게 마무리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2255&quot; data-start=&quot;2248&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;2492&quot; data-start=&quot;2257&quot; data-ke-size=&quot;size16&quot;&gt;MSA는 설계와 분리 구조가 잘 되었다고 끝나는 것이 아니다.&lt;br /&gt;&lt;b&gt;운영과 성능을 관리할 수 있는 체계와 대응 전략이 함께 준비되어야 진정한 마이크로서비스 시스템이 된다.&lt;/b&gt;&lt;br /&gt;지연, 병목, 장애 전파, 데이터 처리 이슈는 대부분 예측 가능한 영역이며, 위에서 소개한 전략들을 적용하면 충분히 사전에 차단 가능하다.&lt;br /&gt;특히 &lt;b&gt;모니터링 &amp;rarr; 자동 대응 &amp;rarr; 장애 전파 격리&lt;/b&gt; 구조를 갖추는 것이 가장 이상적인 형태다.&lt;/p&gt;
&lt;h2 data-end=&quot;2509&quot; data-start=&quot;2494&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2807&quot; data-start=&quot;2511&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2654&quot; data-start=&quot;2511&quot;&gt;&lt;a data-end=&quot;2652&quot; data-start=&quot;2513&quot;&gt;Spring Boot Performance Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;2716&quot; data-start=&quot;2655&quot;&gt;&lt;a data-end=&quot;2714&quot; data-start=&quot;2657&quot;&gt;Resilience4j 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;2807&quot; data-start=&quot;2717&quot;&gt;&lt;a data-end=&quot;2807&quot; data-start=&quot;2719&quot;&gt;MSA에서 성능 병목 해결 전략 - NGINX Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>MSA</category>
      <category>circuitbreaker</category>
      <category>Kafka비동기</category>
      <category>MSA</category>
      <category>MSA장애대응</category>
      <category>Nplus1문제</category>
      <category>Spring성능최적화</category>
      <category>마이크로서비스모니터링</category>
      <category>서비스지연</category>
      <category>성능이슈</category>
      <category>캐시전략</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1067</guid>
      <comments>https://monkeybusiness.tistory.com/1067#entry1067comment</comments>
      <pubDate>Thu, 24 Jul 2025 16:32:48 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] 마이크로서비스 간 트랜잭션: Saga와 Eventual Consistency</title>
      <link>https://monkeybusiness.tistory.com/1066</link>
      <description>&lt;p data-end=&quot;565&quot; data-start=&quot;272&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)에서는 각 서비스가 &lt;b&gt;자신만의 데이터베이스를 갖고 독립적으로 동작&lt;/b&gt;한다.&lt;br /&gt;이 구조는 높은 확장성과 유연성을 제공하지만, 동시에 기존의 &lt;b&gt;ACID 기반 트랜잭션 관리가 불가능해지는 단점&lt;/b&gt;도 함께 발생한다.&lt;br /&gt;즉, 주문 &amp;rarr; 결제 &amp;rarr; 재고 차감 &amp;rarr; 배송 요청 같은 여러 서비스가 참여하는 복잡한 비즈니스 로직에서 &lt;b&gt;트랜잭션이 보장되지 않는다.&lt;/b&gt;&lt;br /&gt;이를 해결하기 위해 등장한 대표적인 전략이 &lt;b&gt;Saga 패턴&lt;/b&gt;과 &lt;b&gt;최종 일관성(Eventual Consistency)&lt;/b&gt; 개념이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yzFxG/btsPvsgctWG/Q3fnU0fjfSyTUX8wV0DCM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yzFxG/btsPvsgctWG/Q3fnU0fjfSyTUX8wV0DCM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yzFxG/btsPvsgctWG/Q3fnU0fjfSyTUX8wV0DCM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyzFxG%2FbtsPvsgctWG%2FQ3fnU0fjfSyTUX8wV0DCM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;588&quot; data-start=&quot;567&quot; data-ke-size=&quot;size26&quot;&gt;✅ 왜 분산 트랜잭션이 어려운가?&lt;/h2&gt;
&lt;p data-end=&quot;694&quot; data-start=&quot;590&quot; data-ke-size=&quot;size16&quot;&gt;기존 모놀리식 시스템에서는 하나의 트랜잭션으로 여러 테이블을 묶고, 실패 시 롤백이 가능했다.&lt;br /&gt;하지만 MSA에서는 서비스마다 데이터베이스가 다르기 때문에 다음과 같은 문제가 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;842&quot; data-start=&quot;696&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;755&quot; data-start=&quot;696&quot;&gt;&lt;b&gt;2PC(Two Phase Commit)&lt;/b&gt;은 비표준 기술이 많고, 성능/장애 복구 이슈가 있다.&lt;/li&gt;
&lt;li data-end=&quot;799&quot; data-start=&quot;756&quot;&gt;서비스 간 네트워크 호출로 인해 &lt;b&gt;트랜잭션이 느리고 불안정&lt;/b&gt;해진다.&lt;/li&gt;
&lt;li data-end=&quot;842&quot; data-start=&quot;800&quot;&gt;하나의 서비스에서 문제가 발생해도 전체 프로세스를 롤백하는 수단이 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;902&quot; data-start=&quot;844&quot; data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;전통적인 트랜잭션 모델 대신 '트랜잭션을 나눠서 처리하고 보상하는 방식'&lt;/b&gt;이 대세가 되었다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;920&quot; data-start=&quot;904&quot; data-ke-size=&quot;size26&quot;&gt;  Saga 패턴이란?&lt;/h2&gt;
&lt;p data-end=&quot;1049&quot; data-start=&quot;922&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Saga 패턴&lt;/b&gt;은 여러 개의 지역 트랜잭션(Local Transaction)을 순차적으로 실행하고, 중간에 실패할 경우 이미 수행된 작업을 &lt;b&gt;보상(Compensation)&lt;/b&gt;하는 방식으로 처리하는 트랜잭션 관리 전략이다.&lt;/p&gt;
&lt;h3 data-end=&quot;1060&quot; data-start=&quot;1051&quot; data-ke-size=&quot;size23&quot;&gt;  특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1257&quot; data-start=&quot;1062&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1119&quot; data-start=&quot;1062&quot;&gt;각 서비스는 자체 DB에서 &lt;b&gt;자기 역할만 처리&lt;/b&gt;하고 성공/실패 여부를 다음 단계로 전달한다.&lt;/li&gt;
&lt;li data-end=&quot;1172&quot; data-start=&quot;1120&quot;&gt;실패 시 이전 단계에서 처리된 작업을 &lt;b&gt;반대로 되돌리는 보상 트랜잭션&lt;/b&gt;이 호출된다.&lt;/li&gt;
&lt;li data-end=&quot;1257&quot; data-start=&quot;1173&quot;&gt;ACID 대신 &lt;b&gt;BASE 모델&lt;/b&gt;을 채택한다. (Basically Available, Soft state, Eventual consistency)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1282&quot; data-start=&quot;1259&quot; data-ke-size=&quot;size23&quot;&gt;  예시 시나리오: 주문 프로세스&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1361&quot; data-start=&quot;1284&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1303&quot; data-start=&quot;1284&quot;&gt;주문 서비스 &amp;rarr; 주문 생성&lt;/li&gt;
&lt;li data-end=&quot;1323&quot; data-start=&quot;1304&quot;&gt;결제 서비스 &amp;rarr; 결제 요청&lt;/li&gt;
&lt;li data-end=&quot;1343&quot; data-start=&quot;1324&quot;&gt;재고 서비스 &amp;rarr; 재고 차감&lt;/li&gt;
&lt;li data-end=&quot;1361&quot; data-start=&quot;1344&quot;&gt;배송 서비스 &amp;rarr; 출고 요청&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1427&quot; data-start=&quot;1363&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 만약 3번에서 실패하면?&lt;br /&gt;&amp;rarr; 재고 서비스 실패 &amp;rarr; 결제 취소 &amp;rarr; 주문 취소 등 &lt;b&gt;역방향 보상 작업&lt;/b&gt; 수행&lt;/p&gt;
&lt;h2 data-end=&quot;1449&quot; data-start=&quot;1429&quot; data-ke-size=&quot;size26&quot;&gt;  Saga 패턴의 구현 방식&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1623&quot; data-start=&quot;1451&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;방식&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1548&quot; data-start=&quot;1479&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1507&quot; data-start=&quot;1479&quot;&gt;&lt;b&gt;Choreography (이벤트 기반)&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1548&quot; data-start=&quot;1507&quot;&gt;각 서비스가 이벤트를 구독하고 처리하며, 다음 서비스에 이벤트 발행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1623&quot; data-start=&quot;1549&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1581&quot; data-start=&quot;1549&quot;&gt;&lt;b&gt;Orchestration (중앙 제어자 방식)&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1623&quot; data-start=&quot;1581&quot;&gt;중앙 컨트롤러(Orchestrator)가 전체 흐름을 관리하고 명령 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #000000; font-size: 1.44em; letter-spacing: -1px;&quot;&gt;1. Choreography 방식&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1735&quot; data-start=&quot;1649&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1682&quot; data-start=&quot;1649&quot;&gt;이벤트 기반 (Kafka, RabbitMQ 등 사용)&lt;/li&gt;
&lt;li data-end=&quot;1699&quot; data-start=&quot;1683&quot;&gt;서비스 간 느슨한 결합&lt;/li&gt;
&lt;li data-end=&quot;1735&quot; data-start=&quot;1700&quot;&gt;흐름이 분산되어 있어 &lt;b&gt;복잡한 시나리오는 추적이 어려움&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1735&quot; data-start=&quot;1700&quot;&gt;간단한 업무에 적용하기 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1865&quot; data-start=&quot;1842&quot; data-ke-size=&quot;size23&quot;&gt;2. Orchestration 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1943&quot; data-start=&quot;1867&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1903&quot; data-start=&quot;1867&quot;&gt;중앙 오케스트레이터(예: 주문 서비스)가 전체 흐름을 제어&lt;/li&gt;
&lt;li data-end=&quot;1924&quot; data-start=&quot;1904&quot;&gt;상태 추적과 장애 대응이 명확&lt;/li&gt;
&lt;li data-end=&quot;1943&quot; data-start=&quot;1925&quot;&gt;결합도가 다소 높아질 수 있음&lt;/li&gt;
&lt;li data-end=&quot;1943&quot; data-start=&quot;1925&quot;&gt;트랜잭션을 단계별로 수행하고 실패 시 보상 트랜잭션으로 롤백 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2096&quot; data-start=&quot;2069&quot; data-ke-size=&quot;size26&quot;&gt;⏳ Eventual Consistency란?&lt;/h2&gt;
&lt;p data-end=&quot;2251&quot; data-start=&quot;2098&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Eventual Consistency(최종 일관성)&lt;/b&gt;는 마이크로서비스 간 분산 트랜잭션에서 &lt;b&gt;즉시 일관성을 포기하고, 시간이 지나면 데이터가 일치하도록 설계하는 전략&lt;/b&gt;이다.&lt;br /&gt;즉, 데이터가 모든 시스템에 &lt;b&gt;즉시 반영되지는 않지만, 결국엔 동일한 상태가 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2343&quot; data-start=&quot;2253&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 결제가 성공했지만 재고 차감이 잠시 지연되더라도,&lt;br /&gt;재시도, 큐 기반 처리 등을 통해 결국에는 &lt;b&gt;데이터 상태가 완전하게 수렴&lt;/b&gt;되는 것을 의미한다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2360&quot; data-start=&quot;2345&quot; data-ke-size=&quot;size26&quot;&gt; ️ 실전 구현 도구&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2643&quot; data-start=&quot;2362&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;기능&lt;/td&gt;
&lt;td&gt;도구&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2457&quot; data-start=&quot;2402&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2412&quot; data-start=&quot;2402&quot;&gt;이벤트 브로커&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;2430&quot; data-start=&quot;2412&quot;&gt;Kafka, RabbitMQ&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2457&quot; data-start=&quot;2430&quot;&gt;서비스 간 비동기 통신을 위한 메시지 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2523&quot; data-start=&quot;2458&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2471&quot; data-start=&quot;2458&quot;&gt;Saga 프레임워크&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;2498&quot; data-start=&quot;2471&quot;&gt;Axon, Camunda, Eventuate&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2523&quot; data-start=&quot;2498&quot;&gt;오케스트레이션, 상태 추적 자동화 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2594&quot; data-start=&quot;2524&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2533&quot; data-start=&quot;2524&quot;&gt;메시지 보장&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;2581&quot; data-start=&quot;2533&quot;&gt;Outbox Pattern, Transactional Event Publisher&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2594&quot; data-start=&quot;2581&quot;&gt;메시지 유실 방지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2643&quot; data-start=&quot;2595&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2604&quot; data-start=&quot;2595&quot;&gt;상태 저장소&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;2631&quot; data-start=&quot;2604&quot;&gt;Redis, DB, Kafka Streams&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2643&quot; data-start=&quot;2631&quot;&gt;트랜잭션 상태 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2655&quot; data-start=&quot;2645&quot; data-ke-size=&quot;size26&quot;&gt;  실무 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2951&quot; data-start=&quot;2657&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2712&quot; data-start=&quot;2657&quot;&gt;Saga는 실패 가능성을 항상 고려해야 하므로 &lt;b&gt;보상 트랜잭션을 반드시 정의&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2765&quot; data-start=&quot;2713&quot;&gt;각 서비스는 반드시 &lt;b&gt;자신의 상태를 명확히 판단할 수 있는 로직&lt;/b&gt;을 포함해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2806&quot; data-start=&quot;2766&quot;&gt;이벤트 중복 처리 방지, 메시지 재시도 로직 등도 고려해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2885&quot; data-start=&quot;2807&quot;&gt;Kafka 기반 구현 시에는 &lt;b&gt;Idempotent Producer 설정&lt;/b&gt; 및 &lt;b&gt;Exactly Once 처리 전략&lt;/b&gt;이 중요하다.&lt;/li&gt;
&lt;li data-end=&quot;2951&quot; data-start=&quot;2886&quot;&gt;보상 실패까지 대비하려면 &lt;b&gt;Dead Letter Queue&lt;/b&gt;, &lt;b&gt;수동 조치 시스템&lt;/b&gt;도 함께 설계해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2960&quot; data-start=&quot;2953&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3185&quot; data-start=&quot;2962&quot; data-ke-size=&quot;size16&quot;&gt;MSA에서의 트랜잭션은 단일 시스템에서처럼 처리할 수 없다.&lt;br /&gt;대신 &lt;b&gt;각 서비스는 독립적으로 성공하고, 실패 시에는 보상하는 구조로 설계&lt;/b&gt;해야 한다.&lt;br /&gt;Saga 패턴과 Eventual Consistency는 분산 환경에서의 데이터 정합성과 안정성을 확보하는 핵심 전략이다.&lt;br /&gt;정답은 없지만, &lt;b&gt;서비스의 특성과 운영 여건에 맞는 트랜잭션 분해 전략을 수립하는 것이 가장 중요한 포인트&lt;/b&gt;다.&lt;/p&gt;
&lt;h2 data-end=&quot;3202&quot; data-start=&quot;3187&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3485&quot; data-start=&quot;3204&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3294&quot; data-start=&quot;3204&quot;&gt;&lt;a data-end=&quot;3292&quot; data-start=&quot;3206&quot;&gt;Saga Pattern 설명 - microservices.io&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3394&quot; data-start=&quot;3295&quot;&gt;&lt;a data-end=&quot;3392&quot; data-start=&quot;3297&quot;&gt;Eventuate Tram Framework (Java 기반 Saga 구현체)&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3485&quot; data-start=&quot;3395&quot;&gt;&lt;a href=&quot;https://spring.io/guides/tutorials/spring-cloud-kafka&quot; data-end=&quot;3485&quot; data-start=&quot;3397&quot;&gt;Spring Cloud + Kafka 기반 Saga 예제&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>MSA</category>
      <category>choreography</category>
      <category>EventualConsistency</category>
      <category>Kafka트랜잭션</category>
      <category>MSA</category>
      <category>MSA데이터일관성</category>
      <category>orchestration</category>
      <category>Saga패턴</category>
      <category>마이크로서비스트랜잭션</category>
      <category>보상트랜잭션</category>
      <category>분산트랜잭션</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1066</guid>
      <comments>https://monkeybusiness.tistory.com/1066#entry1066comment</comments>
      <pubDate>Thu, 24 Jul 2025 15:41:00 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] 계약 테스트와 통합 테스트 전략 비교</title>
      <link>https://monkeybusiness.tistory.com/1065</link>
      <description>&lt;p data-end=&quot;555&quot; data-start=&quot;224&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 서비스 간에 명확하게 분리된 구조이지만, 이들이 서로 통신하지 않는다면 아무 의미가 없다.&lt;br /&gt;즉, 독립적으로 개발하더라도 서비스 간의 연동(REST API, 메시지, 이벤트 등)은 반드시 정확해야 한다.&lt;br /&gt;문제는 각각 독립적으로 개발되기 때문에 &lt;b&gt;한쪽 변경으로 인해 다른 서비스가 깨지는 문제&lt;/b&gt;가 자주 발생한다.&lt;br /&gt;이러한 문제를 방지하기 위해 사용되는 테스트 기법이 바로 &lt;b&gt;계약 테스트(Contract Test)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;647&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D8svy/btsPwIPxukM/F7lYQGeUVQGkklFUejzGc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D8svy/btsPwIPxukM/F7lYQGeUVQGkklFUejzGc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D8svy/btsPwIPxukM/F7lYQGeUVQGkklFUejzGc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD8svy%2FbtsPwIPxukM%2FF7lYQGeUVQGkklFUejzGc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;647&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;647&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;570&quot; data-start=&quot;557&quot; data-ke-size=&quot;size26&quot;&gt;✅ 통합 테스트란?&lt;/h2&gt;
&lt;p data-end=&quot;721&quot; data-start=&quot;572&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;통합 테스트(Integration Test)&lt;/b&gt;는 두 개 이상의 컴포넌트(또는 서비스)가 &lt;b&gt;정상적으로 연동되는지&lt;/b&gt;를 실제로 호출하여 검증하는 테스트이다.&lt;br /&gt;예를 들어 A 서비스가 B 서비스의 API를 호출했을 때, 응답 값이 기대한 형태인지 확인하는 식이다.&lt;/p&gt;
&lt;h3 data-end=&quot;732&quot; data-start=&quot;723&quot; data-ke-size=&quot;size23&quot;&gt;  특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;837&quot; data-start=&quot;734&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;764&quot; data-start=&quot;734&quot;&gt;실제 HTTP 통신 또는 DB 연결이 발생한다.&lt;/li&gt;
&lt;li data-end=&quot;795&quot; data-start=&quot;765&quot;&gt;외부 시스템이 준비되어 있어야 테스트 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;837&quot; data-start=&quot;796&quot;&gt;환경 의존성이 크기 때문에 &lt;b&gt;속도가 느리고 안정성도 낮은 편&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;847&quot; data-start=&quot;839&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;914&quot; data-start=&quot;849&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;882&quot; data-start=&quot;849&quot;&gt;실제 환경과 거의 동일한 조건에서 테스트할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;914&quot; data-start=&quot;883&quot;&gt;통합 오류나 배포 간 문제를 사전에 파악할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;924&quot; data-start=&quot;916&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;989&quot; data-start=&quot;926&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;944&quot; data-start=&quot;926&quot;&gt;테스트 유지보수가 어렵다.&lt;/li&gt;
&lt;li data-end=&quot;972&quot; data-start=&quot;945&quot;&gt;외부 의존성 때문에 테스트가 자주 깨진다.&lt;/li&gt;
&lt;li data-end=&quot;989&quot; data-start=&quot;973&quot;&gt;실행 시간이 오래 걸린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1005&quot; data-start=&quot;991&quot; data-ke-size=&quot;size26&quot;&gt;  계약 테스트란?&lt;/h2&gt;
&lt;p data-end=&quot;1212&quot; data-start=&quot;1007&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;계약 테스트(Contract Test)&lt;/b&gt;는 서비스 간의 &lt;b&gt;계약(API 요청/응답 형식, 메시지 포맷 등)&lt;/b&gt;이 지켜지는지를 테스트하는 방식이다.&lt;br /&gt;소비자(Consumer)와 제공자(Provider)가 사전에 약속한 스펙을 기준으로 &lt;b&gt;독립적으로 테스트&lt;/b&gt;할 수 있다.&lt;br /&gt;대표적인 도구로는 &lt;b&gt;Spring Cloud Contract, Pact&lt;/b&gt; 등이 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;1229&quot; data-start=&quot;1214&quot; data-ke-size=&quot;size23&quot;&gt;  작동 방식 요약&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1347&quot; data-start=&quot;1231&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1268&quot; data-start=&quot;1231&quot;&gt;소비자 서비스가 필요한 API 요청/응답 형식을 정의한다.&lt;/li&gt;
&lt;li data-end=&quot;1304&quot; data-start=&quot;1269&quot;&gt;그 정의를 계약 파일(JSON 또는 DSL)로 만든다.&lt;/li&gt;
&lt;li data-end=&quot;1347&quot; data-start=&quot;1305&quot;&gt;제공자 서비스는 이 계약을 기준으로 응답을 생성하고 테스트를 수행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-end=&quot;1357&quot; data-start=&quot;1349&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1497&quot; data-start=&quot;1359&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1387&quot; data-start=&quot;1359&quot;&gt;양쪽 서비스를 독립적으로 테스트할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;1424&quot; data-start=&quot;1388&quot;&gt;실제 API 호출 없이 빠르고 안정적인 테스트가 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;1453&quot; data-start=&quot;1425&quot;&gt;&lt;b&gt;CI 파이프라인에 통합하기 적합&lt;/b&gt;하다.&lt;/li&gt;
&lt;li data-end=&quot;1497&quot; data-start=&quot;1454&quot;&gt;변경된 API가 다른 서비스에 영향을 주지 않는지 조기에 검출할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1507&quot; data-start=&quot;1499&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1611&quot; data-start=&quot;1509&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1540&quot; data-start=&quot;1509&quot;&gt;초기 설정과 계약 정의에 시간과 노력이 필요하다.&lt;/li&gt;
&lt;li data-end=&quot;1576&quot; data-start=&quot;1541&quot;&gt;계약 파일이 변경되면 테스트 양쪽 모두를 조정해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;1611&quot; data-start=&quot;1577&quot;&gt;API의 의미적 오류(비즈니스 로직 차이)는 잡지 못한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1638&quot; data-start=&quot;1613&quot; data-ke-size=&quot;size26&quot;&gt;  통합 테스트 vs 계약 테스트 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1941&quot; data-start=&quot;1640&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;통합 테스트&lt;/td&gt;
&lt;td&gt;계약 테스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1746&quot; data-start=&quot;1705&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1710&quot; data-start=&quot;1705&quot;&gt;목적&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1727&quot; data-start=&quot;1710&quot;&gt;실제 시스템 간 통신 검증&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1746&quot; data-start=&quot;1727&quot;&gt;요청/응답 형식의 약속 검증&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1779&quot; data-start=&quot;1747&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1755&quot; data-start=&quot;1747&quot;&gt;실행 환경&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1767&quot; data-start=&quot;1755&quot;&gt;외부 시스템 필요&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1779&quot; data-start=&quot;1767&quot;&gt;독립 실행 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1800&quot; data-start=&quot;1780&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1789&quot; data-start=&quot;1780&quot;&gt;테스트 속도&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1794&quot; data-start=&quot;1789&quot;&gt;느림&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1800&quot; data-start=&quot;1794&quot;&gt;빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1824&quot; data-start=&quot;1801&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1807&quot; data-start=&quot;1801&quot;&gt;신뢰성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1817&quot; data-start=&quot;1807&quot;&gt;환경 영향 큼&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1824&quot; data-start=&quot;1817&quot;&gt;안정적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1869&quot; data-start=&quot;1825&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1834&quot; data-start=&quot;1825&quot;&gt;적용 난이도&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1851&quot; data-start=&quot;1834&quot;&gt;간단하지만 유지보수 어려움&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1869&quot; data-start=&quot;1851&quot;&gt;초기 설정 복잡하나 효율적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1941&quot; data-start=&quot;1870&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1878&quot; data-start=&quot;1870&quot;&gt;대표 도구&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1910&quot; data-start=&quot;1878&quot;&gt;TestRestTemplate, RestAssured&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1941&quot; data-start=&quot;1910&quot;&gt;Spring Cloud Contract, Pact&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1974&quot; data-start=&quot;1943&quot; data-ke-size=&quot;size26&quot;&gt; ️ Spring Cloud Contract 예시&lt;/h2&gt;
&lt;h3 data-end=&quot;2001&quot; data-start=&quot;1976&quot; data-ke-size=&quot;size23&quot;&gt;1. 계약 정의 (Groovy DSL)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753322613555&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Contract.make {
    request {
        method 'GET'
        url '/api/users/1'
    }
    response {
        status 200
        body(
            id: 1,
            name: 'Alice'
        )
        headers {
            contentType(applicationJson())
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2303&quot; data-start=&quot;2284&quot; data-ke-size=&quot;size23&quot;&gt;2. 자동으로 Stub 생성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2396&quot; data-start=&quot;2305&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2347&quot; data-start=&quot;2305&quot;&gt;이 계약을 기반으로 WireMock 기반의 Stub 서버가 생성된다.&lt;/li&gt;
&lt;li data-end=&quot;2396&quot; data-start=&quot;2348&quot;&gt;소비자는 실제 서비스를 호출하지 않고 &lt;b&gt;이 Stub을 통해 테스트를 수행&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753322626203&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
public void testUserApi() {
    given()
      .port(port)
      .when()
      .get(&quot;/api/users/1&quot;)
      .then()
      .statusCode(200)
      .body(&quot;name&quot;, equalTo(&quot;Alice&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2609&quot; data-start=&quot;2594&quot; data-ke-size=&quot;size23&quot;&gt;3. 제공자 측 검증&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2707&quot; data-start=&quot;2611&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2656&quot; data-start=&quot;2611&quot;&gt;계약 파일을 기준으로 실제 API 응답이 스펙을 만족하는지 자동 검증된다.&lt;/li&gt;
&lt;li data-end=&quot;2707&quot; data-start=&quot;2657&quot;&gt;이를 통해 &lt;b&gt;API 변경 시 다른 서비스에 미치는 영향&lt;/b&gt;을 조기에 파악할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2723&quot; data-start=&quot;2709&quot; data-ke-size=&quot;size26&quot;&gt;  실무 적용 전략&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2906&quot; data-start=&quot;2725&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2762&quot; data-start=&quot;2725&quot;&gt;&lt;b&gt;간단한 연동 + 빠른 확인&lt;/b&gt;이 필요할 때는 통합 테스트&lt;/li&gt;
&lt;li data-end=&quot;2811&quot; data-start=&quot;2763&quot;&gt;&lt;b&gt;서비스 간 계약이 자주 바뀌고, 배포 주기가 빠른 환경&lt;/b&gt;에서는 계약 테스트&lt;/li&gt;
&lt;li data-end=&quot;2906&quot; data-start=&quot;2812&quot;&gt;이상적인 전략은 두 가지 테스트를 &lt;b&gt;조합해서 사용하는 것&lt;/b&gt;이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2906&quot; data-start=&quot;2856&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2878&quot; data-start=&quot;2856&quot;&gt;계약 테스트 &amp;rarr; API 형식 검증&lt;/li&gt;
&lt;li data-end=&quot;2906&quot; data-start=&quot;2881&quot;&gt;통합 테스트 &amp;rarr; 실제 배포 환경 연동 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2915&quot; data-start=&quot;2908&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3114&quot; data-start=&quot;2917&quot; data-ke-size=&quot;size16&quot;&gt;MSA에서의 테스트는 단일 애플리케이션보다 훨씬 중요하고 복잡하다.&lt;br /&gt;통합 테스트는 실제 시스템 간 연동 확인에 효과적이고, 계약 테스트는 빠르고 안정적인 검증에 유리하다.&lt;br /&gt;두 테스트를 적절히 조합하면 &lt;b&gt;API 스펙 오류, 연동 실패, 통신 문제를 미리 방지할 수 있으며&lt;/b&gt;, 서비스 간 결합도를 유지하면서도 &lt;b&gt;배포 안정성을 높일 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-end=&quot;3131&quot; data-start=&quot;3116&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3355&quot; data-start=&quot;3133&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3216&quot; data-start=&quot;3133&quot;&gt;&lt;a href=&quot;https://spring.io/projects/spring-cloud-contract&quot; data-end=&quot;3214&quot; data-start=&quot;3135&quot;&gt;Spring Cloud Contract 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3252&quot; data-start=&quot;3217&quot;&gt;&lt;a data-end=&quot;3250&quot; data-start=&quot;3219&quot;&gt;Pact 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3355&quot; data-start=&quot;3253&quot;&gt;&lt;a data-end=&quot;3355&quot; data-start=&quot;3255&quot;&gt;Testing Strategies in MSA - Martin Fowler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3464&quot; data-start=&quot;3381&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>MSA</category>
      <category>MSA연동테스트</category>
      <category>Pact</category>
      <category>SpringCloudContract</category>
      <category>계약테스트</category>
      <category>마이크로서비스테스트</category>
      <category>분산시스템검증</category>
      <category>서비스간통신검증</category>
      <category>테스트전략</category>
      <category>통합테스트</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1065</guid>
      <comments>https://monkeybusiness.tistory.com/1065#entry1065comment</comments>
      <pubDate>Thu, 24 Jul 2025 14:43:28 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] Sleuth, Zipkin으로 분산 추적 구현하기</title>
      <link>https://monkeybusiness.tistory.com/1064</link>
      <description>&lt;p data-end=&quot;537&quot; data-start=&quot;219&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)에서는 하나의 사용자 요청이 여러 서비스를 연쇄적으로 호출하며 처리된다.&lt;br /&gt;예를 들어 사용자가 주문을 하면, 주문 서비스가 호출되고 이어서 결제 서비스, 재고 서비스, 알림 서비스 등 수 개의 마이크로서비스가 함께 동작한다.&lt;br /&gt;이런 구조에서는 장애나 지연이 발생했을 때 &lt;b&gt;&quot;어디서 문제가 생겼는지&quot;&lt;/b&gt;를 빠르게 파악하는 것이 매우 중요하다.&lt;br /&gt;이를 가능하게 해주는 기술이 바로 &lt;b&gt;분산 추적(Distributed Tracing)&lt;/b&gt;이며, Spring Cloud에서 가장 널리 사용되는 조합이 &lt;b&gt;Sleuth + Zipkin&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS8sWW/btsPv7oG63c/yzS3skB1iAWKkrC8qyCJy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS8sWW/btsPv7oG63c/yzS3skB1iAWKkrC8qyCJy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS8sWW/btsPv7oG63c/yzS3skB1iAWKkrC8qyCJy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS8sWW%2FbtsPv7oG63c%2FyzS3skB1iAWKkrC8qyCJy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;552&quot; data-start=&quot;539&quot; data-ke-size=&quot;size26&quot;&gt;✅ 분산 추적이란?&lt;/h2&gt;
&lt;p data-end=&quot;700&quot; data-start=&quot;554&quot; data-ke-size=&quot;size16&quot;&gt;분산 추적은 &lt;b&gt;하나의 요청(Request)이 여러 서비스 간을 오갈 때 그 흐름을 고유한 Trace ID로 추적&lt;/b&gt;하는 기술이다.&lt;br /&gt;각 서비스에서 처리 시간을 기록하고, 전체 흐름을 타임라인으로 시각화해 &lt;b&gt;지연 지점, 장애 발생 지점&lt;/b&gt;을 확인할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;716&quot; data-start=&quot;702&quot; data-ke-size=&quot;size23&quot;&gt;  왜 필요한가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;843&quot; data-start=&quot;718&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;743&quot; data-start=&quot;718&quot;&gt;서비스 호출 간 &lt;b&gt;병목 구간 파악&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;770&quot; data-start=&quot;744&quot;&gt;예기치 못한 &lt;b&gt;응답 지연 원인 분석&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;807&quot; data-start=&quot;771&quot;&gt;&lt;b&gt;로그 상호 연관성 확보&lt;/b&gt; (같은 요청임을 파악 가능)&lt;/li&gt;
&lt;li data-end=&quot;843&quot; data-start=&quot;808&quot;&gt;대규모 서비스 구조에서 &lt;b&gt;운영자와 개발자의 관찰력 향상&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;872&quot; data-start=&quot;845&quot; data-ke-size=&quot;size26&quot;&gt;  Spring Cloud Sleuth란?&lt;/h2&gt;
&lt;p data-end=&quot;973&quot; data-start=&quot;874&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring Cloud Sleuth&lt;/b&gt;는 Spring Boot 기반 애플리케이션에서 &lt;b&gt;자동으로 Trace ID와 Span ID를 생성하고 전파&lt;/b&gt;해주는 분산 추적 도구이다.&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1095&quot; data-start=&quot;975&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;용어&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1043&quot; data-start=&quot;1003&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1018&quot; data-start=&quot;1003&quot;&gt;&lt;b&gt;Trace ID&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1043&quot; data-start=&quot;1018&quot;&gt;하나의 요청 전체를 식별하는 고유 ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1095&quot; data-start=&quot;1044&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1058&quot; data-start=&quot;1044&quot;&gt;&lt;b&gt;Span ID&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1095&quot; data-start=&quot;1058&quot;&gt;하나의 작업 단위 (Service or Method) 식별 ID&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Sleuth는 모든 로그에 Trace ID/Span ID를 자동으로 붙여주기 때문에, 로그만으로도 추적이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1175&quot; data-start=&quot;1163&quot; data-ke-size=&quot;size23&quot;&gt;  예시 로그&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753322431371&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[7b0f2e4b9f1a1a16, 7b0f2e4b9f1a1a16] INFO 12345 --- [nio-8080-exec-1] o.s.web.RestController : 처리 시작&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1307&quot; data-start=&quot;1291&quot; data-ke-size=&quot;size26&quot;&gt; ️ Zipkin이란?&lt;/h2&gt;
&lt;p data-end=&quot;1431&quot; data-start=&quot;1309&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Zipkin&lt;/b&gt;은 분산 추적 데이터를 &lt;b&gt;시각화하고 저장하는 서버&lt;/b&gt;이다.&lt;br /&gt;Sleuth가 생성한 Trace 정보를 Zipkin에 전송하면, Zipkin은 이를 &lt;b&gt;웹 대시보드에서 타임라인 형태로 시각화&lt;/b&gt;해준다.&lt;/p&gt;
&lt;h3 data-end=&quot;1451&quot; data-start=&quot;1433&quot; data-ke-size=&quot;size23&quot;&gt;✅ Zipkin 주요 기능&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1555&quot; data-start=&quot;1453&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1481&quot; data-start=&quot;1453&quot;&gt;요청 흐름을 서비스 간 호출 순서대로 시각화&lt;/li&gt;
&lt;li data-end=&quot;1504&quot; data-start=&quot;1482&quot;&gt;지연 시간, 에러 발생 구간 파악&lt;/li&gt;
&lt;li data-end=&quot;1523&quot; data-start=&quot;1505&quot;&gt;REST 기반 API 제공&lt;/li&gt;
&lt;li data-end=&quot;1555&quot; data-start=&quot;1524&quot;&gt;Spring Cloud Sleuth와 기본 연동 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1585&quot; data-start=&quot;1557&quot; data-ke-size=&quot;size26&quot;&gt; ️ Sleuth + Zipkin 적용 방법&lt;/h2&gt;
&lt;h3 data-end=&quot;1609&quot; data-start=&quot;1587&quot; data-ke-size=&quot;size23&quot;&gt;1. 의존성 추가 (Gradle)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753322440523&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
implementation 'org.springframework.cloud:spring-cloud-starter-zipkin'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1793&quot; data-start=&quot;1768&quot; data-ke-size=&quot;size23&quot;&gt;2. application.yml 설정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753322446562&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  zipkin:
    base-url: http://localhost:9411
    enabled: true
  sleuth:
    sampler:
      probability: 1.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2022&quot; data-start=&quot;1926&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1989&quot; data-start=&quot;1926&quot;&gt;probability는 1.0으로 설정하면 100% 추적하며, 운영환경에서는 0.1(10%) 정도 추천&lt;/li&gt;
&lt;li data-end=&quot;2022&quot; data-start=&quot;1990&quot;&gt;Zipkin 서버는 기본적으로 9411 포트를 사용한다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2052&quot; data-start=&quot;2024&quot; data-ke-size=&quot;size23&quot;&gt;3. Zipkin 서버 실행 (Docker)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753322455826&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d -p 9411:9411 openzipkin/zipkin&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2129&quot; data-start=&quot;2112&quot; data-ke-size=&quot;size23&quot;&gt;4. 로그 + UI 확인&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2244&quot; data-start=&quot;2131&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2165&quot; data-start=&quot;2131&quot;&gt;로그에 Trace ID가 포함되어 전체 흐름 추적 가능&lt;/li&gt;
&lt;li data-end=&quot;2207&quot; data-start=&quot;2166&quot;&gt;Zipkin 대시보드 접속: &lt;a href=&quot;http://localhost:9411&quot; data-end=&quot;2205&quot; data-start=&quot;2184&quot;&gt;http://localhost:9411&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;2244&quot; data-start=&quot;2208&quot;&gt;요청 흐름 확인: 서비스 호출 간 시간 소요, 실패 지점 파악&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2275&quot; data-start=&quot;2246&quot; data-ke-size=&quot;size26&quot;&gt;  Sleuth와 Kafka 연동 시 고려사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2474&quot; data-start=&quot;2277&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2355&quot; data-start=&quot;2277&quot;&gt;Kafka 메시지 기반 통신에서도 Trace 정보를 전파하려면 &lt;b&gt;Headers에 Trace ID/Span ID를 포함&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2413&quot; data-start=&quot;2356&quot;&gt;Micrometer Tracing 또는 Brave를 통해 Kafka의 수동 트레이싱도 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;2474&quot; data-start=&quot;2414&quot;&gt;메시지 컨슈머에서도 TraceContextExtractor를 활용하면 전체 트랜잭션 연결이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2489&quot; data-start=&quot;2476&quot; data-ke-size=&quot;size26&quot;&gt;  실무 적용 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2772&quot; data-start=&quot;2491&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2570&quot; data-start=&quot;2491&quot;&gt;각 서비스는 Sleuth가 자동으로 Trace ID를 부여하기 때문에 &lt;b&gt;별도 로직 없이 로그만 보면 연관 요청을 파악할 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2647&quot; data-start=&quot;2571&quot;&gt;Zipkin 서버는 &lt;b&gt;내부 네트워크에서 운영&lt;/b&gt;하거나 &lt;b&gt;ELK Stack과 연계&lt;/b&gt;해 로그 기반 추적을 보완하는 방식도 좋다.&lt;/li&gt;
&lt;li data-end=&quot;2691&quot; data-start=&quot;2648&quot;&gt;퍼포먼스 부담이 크지 않아 &lt;b&gt;개발 환경에서도 쉽게 도입 가능&lt;/b&gt;하다.&lt;/li&gt;
&lt;li data-end=&quot;2772&quot; data-start=&quot;2692&quot;&gt;&lt;b&gt;Spring Cloud Gateway&lt;/b&gt;와 함께 사용하면 &lt;b&gt;API Gateway &amp;rarr; 서비스 &amp;rarr; DB까지 전체 흐름 추적이 가능&lt;/b&gt;하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2781&quot; data-start=&quot;2774&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;2980&quot; data-start=&quot;2783&quot; data-ke-size=&quot;size16&quot;&gt;분산 추적은 마이크로서비스 구조의 &lt;b&gt;투명성과 관찰 가능성(observability)&lt;/b&gt;을 확보하는 가장 효과적인 방법이다.&lt;br /&gt;Sleuth는 로그에 추적 정보를 남기고, Zipkin은 이를 시각화하여 분석 가능하게 해준다.&lt;br /&gt;특히 MSA 구조에서는 서비스 수가 많아 장애 원인 파악이 어려워지기 때문에, &lt;b&gt;분산 추적은 필수 인프라 구성요소&lt;/b&gt;이다.&lt;/p&gt;
&lt;h2 data-end=&quot;2997&quot; data-start=&quot;2982&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3222&quot; data-start=&quot;2999&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3078&quot; data-start=&quot;2999&quot;&gt;&lt;a href=&quot;https://spring.io/projects/spring-cloud-sleuth&quot; data-end=&quot;3076&quot; data-start=&quot;3001&quot;&gt;Spring Cloud Sleuth 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3118&quot; data-start=&quot;3079&quot;&gt;&lt;a data-end=&quot;3116&quot; data-start=&quot;3081&quot;&gt;Zipkin 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3222&quot; data-start=&quot;3119&quot;&gt;&lt;a data-end=&quot;3222&quot; data-start=&quot;3121&quot;&gt;Spring Sleuth + Zipkin 가이드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3330&quot; data-start=&quot;3248&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>MSA</category>
      <category>MSA장애분석</category>
      <category>Observability</category>
      <category>Sleuth</category>
      <category>springcloud</category>
      <category>traceId</category>
      <category>Zipkin</category>
      <category>마이크로서비스추적</category>
      <category>분산추적</category>
      <category>서비스흐름분석</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1064</guid>
      <comments>https://monkeybusiness.tistory.com/1064#entry1064comment</comments>
      <pubDate>Thu, 24 Jul 2025 13:41:49 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] Prometheus, Grafana로 모니터링 체계 구축하기</title>
      <link>https://monkeybusiness.tistory.com/1063</link>
      <description>&lt;p data-end=&quot;438&quot; data-start=&quot;222&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 서비스가 작고 많기 때문에 시스템 전체의 상태를 실시간으로 모니터링하지 않으면 장애를 감지하기 어렵다.&lt;br /&gt;전통적인 로그 기반 모니터링만으로는 서비스 간 호출, 응답 시간, 시스템 리소스 사용량을 효율적으로 파악할 수 없다.&lt;br /&gt;이러한 문제를 해결하기 위해 가장 많이 사용되는 모니터링 도구가 바로 &lt;b&gt;Prometheus&lt;/b&gt;와 &lt;b&gt;Grafana&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vjPhG/btsPvC3RaDG/N6Ea1LRBtihAezWCIaIVo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vjPhG/btsPvC3RaDG/N6Ea1LRBtihAezWCIaIVo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vjPhG/btsPvC3RaDG/N6Ea1LRBtihAezWCIaIVo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvjPhG%2FbtsPvC3RaDG%2FN6Ea1LRBtihAezWCIaIVo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;463&quot; data-start=&quot;440&quot; data-ke-size=&quot;size26&quot;&gt;✅ MSA에서 모니터링이 중요한 이유&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;637&quot; data-start=&quot;465&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;502&quot; data-start=&quot;465&quot;&gt;서비스 수가 많아지며 &lt;b&gt;장애의 원인 파악이 어려워진다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;548&quot; data-start=&quot;503&quot;&gt;각 서비스가 독립적으로 배포되므로 &lt;b&gt;개별 성능 상태를 추적해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;588&quot; data-start=&quot;549&quot;&gt;부하 증가나 리소스 이상을 빠르게 파악하고 자동 대응해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;637&quot; data-start=&quot;589&quot;&gt;배포 이후 성능 하락, 트래픽 이상, 장애 조짐을 &lt;b&gt;선제적으로 감지해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;691&quot; data-start=&quot;639&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;수집 &amp;rarr; 저장 &amp;rarr; 시각화 &amp;rarr; 알람&lt;/b&gt;의 전 과정을 자동화한 모니터링 체계가 필요하다.&lt;/p&gt;
&lt;h2 data-end=&quot;711&quot; data-start=&quot;693&quot; data-ke-size=&quot;size26&quot;&gt;  Prometheus란?&lt;/h2&gt;
&lt;p data-end=&quot;860&quot; data-start=&quot;713&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Prometheus&lt;/b&gt;는 CNCF(Cloud Native Computing Foundation)의 대표적인 오픈소스 &lt;b&gt;시계열 모니터링 시스템&lt;/b&gt;이다.&lt;br /&gt;특히 &lt;b&gt;Kubernetes와의 통합이 매우 뛰어나며&lt;/b&gt;, 서비스 메트릭 수집 및 알람 설정이 유연하다.&lt;/p&gt;
&lt;h3 data-end=&quot;874&quot; data-start=&quot;862&quot; data-ke-size=&quot;size23&quot;&gt;  주요 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1041&quot; data-start=&quot;876&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;937&quot; data-start=&quot;876&quot;&gt;&lt;b&gt;Pull 방식&lt;/b&gt;의 메트릭 수집 (서비스가 메트릭을 노출 &amp;rarr; Prometheus가 주기적으로 수집)&lt;/li&gt;
&lt;li data-end=&quot;970&quot; data-start=&quot;938&quot;&gt;&lt;b&gt;시계열 데이터 저장&lt;/b&gt; 및 쿼리 (PromQL)&lt;/li&gt;
&lt;li data-end=&quot;1001&quot; data-start=&quot;971&quot;&gt;&lt;b&gt;AlertManager&lt;/b&gt;를 통한 알림 전송&lt;/li&gt;
&lt;li data-end=&quot;1041&quot; data-start=&quot;1002&quot;&gt;서비스 자체 또는 Sidecar 방식으로 Exporter 설치 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1071&quot; data-start=&quot;1043&quot; data-ke-size=&quot;size23&quot;&gt; ️ Spring Boot에서의 적용 예시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;gradle&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753321381563&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;implementation 'io.micrometer:micrometer-registry-prometheus'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;yml&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753321418186&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;management:
  endpoints:
    web:
      exposure:
        include: prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1286&quot; data-start=&quot;1241&quot; data-ke-size=&quot;size16&quot;&gt;서비스가 /actuator/prometheus 엔드포인트로 메트릭을 노출한다.&lt;/p&gt;
&lt;h2 data-end=&quot;1303&quot; data-start=&quot;1288&quot; data-ke-size=&quot;size26&quot;&gt;  Grafana란?&lt;/h2&gt;
&lt;p data-end=&quot;1430&quot; data-start=&quot;1305&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Grafana&lt;/b&gt;는 Prometheus에서 수집한 시계열 데이터를 &lt;b&gt;대시보드 형태로 시각화&lt;/b&gt;하는 도구이다.&lt;br /&gt;직관적인 UI와 다양한 위젯을 통해 개발자와 운영자가 시스템 상태를 실시간으로 파악할 수 있도록 도와준다.&lt;/p&gt;
&lt;h3 data-end=&quot;1443&quot; data-start=&quot;1432&quot; data-ke-size=&quot;size23&quot;&gt;✅ 주요 기능&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1565&quot; data-start=&quot;1445&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1502&quot; data-start=&quot;1445&quot;&gt;다양한 시계열 데이터 소스 연결 (Prometheus, Loki, Elasticsearch 등)&lt;/li&gt;
&lt;li data-end=&quot;1518&quot; data-start=&quot;1503&quot;&gt;실시간 대시보드 구성&lt;/li&gt;
&lt;li data-end=&quot;1533&quot; data-start=&quot;1519&quot;&gt;사용자별 권한 설정&lt;/li&gt;
&lt;li data-end=&quot;1565&quot; data-start=&quot;1534&quot;&gt;&lt;b&gt;알람 설정&lt;/b&gt; 및 슬랙, 이메일, SMS 등 연동&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1584&quot; data-start=&quot;1567&quot; data-ke-size=&quot;size23&quot;&gt;  대시보드 구성 예시&lt;/h3&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1853&quot; data-start=&quot;1586&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;지표 예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1670&quot; data-start=&quot;1622&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1634&quot; data-start=&quot;1622&quot;&gt;서비스 응답 시간&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;1670&quot; data-start=&quot;1634&quot;&gt;http_server_requests_seconds_max&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1727&quot; data-start=&quot;1671&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1677&quot; data-start=&quot;1671&quot;&gt;에러율&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;1727&quot; data-start=&quot;1677&quot;&gt;http_server_requests_seconds_count (5xx 응답 비율)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1777&quot; data-start=&quot;1728&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1746&quot; data-start=&quot;1728&quot;&gt;CPU, Memory 사용량&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;1777&quot; data-start=&quot;1746&quot;&gt;node_exporter, cadvisor 메트릭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1821&quot; data-start=&quot;1778&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1788&quot; data-start=&quot;1778&quot;&gt;DB 연결 수&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;1821&quot; data-start=&quot;1788&quot;&gt;datasource_active_connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1853&quot; data-start=&quot;1822&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1831&quot; data-start=&quot;1822&quot;&gt;인스턴스 수&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;1853&quot; data-start=&quot;1831&quot;&gt;up, instance count&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1887&quot; data-start=&quot;1855&quot; data-ke-size=&quot;size26&quot;&gt;  Prometheus + Grafana 통합 흐름&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0Jsvo/btsPvhr6NC1/hvQVkXdKqi1wUmgmNmM7xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0Jsvo/btsPvhr6NC1/hvQVkXdKqi1wUmgmNmM7xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0Jsvo/btsPvhr6NC1/hvQVkXdKqi1wUmgmNmM7xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0Jsvo%2FbtsPvhr6NC1%2FhvQVkXdKqi1wUmgmNmM7xK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;63&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2058&quot; data-start=&quot;1967&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1997&quot; data-start=&quot;1967&quot;&gt;Prometheus가 각 서비스에서 메트릭 수집&lt;/li&gt;
&lt;li data-end=&quot;2033&quot; data-start=&quot;1998&quot;&gt;Grafana가 Prometheus를 데이터 소스로 사용&lt;/li&gt;
&lt;li data-end=&quot;2058&quot; data-start=&quot;2034&quot;&gt;실시간 차트, 알람, 히스토리 분석 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2100&quot; data-start=&quot;2060&quot; data-ke-size=&quot;size26&quot;&gt;  알람 설정 예시 (Prometheus AlertManager)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;yml&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753322261395&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;groups:
- name: instance_down
  rules:
  - alert: InstanceDown
    expr: up == 0
    for: 30s
    labels:
      severity: critical
    annotations:
      summary: &quot;Instance {{ $labels.instance }} down&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2359&quot; data-start=&quot;2317&quot; data-ke-size=&quot;size16&quot;&gt;이 설정은 서비스 인스턴스가 30초 동안 응답하지 않으면 경고를 발생시킨다.&lt;/p&gt;
&lt;h2 data-end=&quot;2374&quot; data-start=&quot;2361&quot; data-ke-size=&quot;size26&quot;&gt;  실무 적용 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2684&quot; data-start=&quot;2376&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2444&quot; data-start=&quot;2376&quot;&gt;모든 마이크로서비스에 &lt;b&gt;Micrometer + Prometheus Exporter&lt;/b&gt;를 포함시키는 것이 핵심이다.&lt;/li&gt;
&lt;li data-end=&quot;2481&quot; data-start=&quot;2445&quot;&gt;메트릭은 반드시 &lt;b&gt;표준화된 네이밍&lt;/b&gt;으로 관리해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2553&quot; data-start=&quot;2482&quot;&gt;알람은 &lt;b&gt;임계값 기반(Alert Rule)&lt;/b&gt;과 &lt;b&gt;변화율 기반(Anomaly Detection)&lt;/b&gt;을 혼합해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2634&quot; data-start=&quot;2554&quot;&gt;인프라 상태까지 모니터링하려면 &lt;b&gt;Node Exporter, Kube-State-Metrics, cAdvisor&lt;/b&gt; 등을 함께 사용한다.&lt;/li&gt;
&lt;li data-end=&quot;2684&quot; data-start=&quot;2635&quot;&gt;대시보드는 사용자(개발/운영/보안 등) 역할에 따라 나누어 구성하는 것이 효율적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2693&quot; data-start=&quot;2686&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;2921&quot; data-start=&quot;2695&quot; data-ke-size=&quot;size16&quot;&gt;MSA 환경에서 Prometheus와 Grafana는 &lt;b&gt;가장 실전적인 모니터링 조합&lt;/b&gt;이다.&lt;br /&gt;Prometheus는 강력한 메트릭 수집기이며, Grafana는 직관적인 시각화 도구이다.&lt;br /&gt;이 두 가지를 함께 사용하면 &lt;b&gt;서비스 상태를 실시간으로 파악하고, 장애를 조기에 감지하며, 운영 안정성을 확보할 수 있다.&lt;/b&gt;&lt;br /&gt;모니터링 체계는 더 이상 옵션이 아니라, &lt;b&gt;MSA 운영의 필수 인프라&lt;/b&gt;이다.&lt;/p&gt;
&lt;h2 data-end=&quot;2938&quot; data-start=&quot;2923&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3150&quot; data-start=&quot;2940&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3013&quot; data-start=&quot;2940&quot;&gt;&lt;a data-end=&quot;3011&quot; data-start=&quot;2942&quot;&gt;Prometheus 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3056&quot; data-start=&quot;3014&quot;&gt;&lt;a data-end=&quot;3054&quot; data-start=&quot;3016&quot;&gt;Grafana 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3150&quot; data-start=&quot;3057&quot;&gt;&lt;a data-end=&quot;3150&quot; data-start=&quot;3059&quot;&gt;Spring Boot + Prometheus + Grafana 통합 가이드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>MSA</category>
      <category>Grafana</category>
      <category>Kubernetes모니터링</category>
      <category>micrometer</category>
      <category>MSA</category>
      <category>MSA모니터링</category>
      <category>Prometheus</category>
      <category>SpringActuator</category>
      <category>마이크로서비스운영</category>
      <category>서비스메트릭</category>
      <category>실시간모니터링</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1063</guid>
      <comments>https://monkeybusiness.tistory.com/1063#entry1063comment</comments>
      <pubDate>Thu, 24 Jul 2025 12:40:04 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] MSA에서 CI/CD와 무중단 배포 전략</title>
      <link>https://monkeybusiness.tistory.com/1062</link>
      <description>&lt;p data-end=&quot;397&quot; data-start=&quot;185&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 서비스가 작고 독립적이기 때문에 &lt;b&gt;빠르고 자주 배포&lt;/b&gt;할 수 있는 환경에 최적화되어 있다.&lt;br /&gt;하지만 서비스가 많아질수록 수동 배포는 위험하고, 실시간 트래픽을 처리하는 구조에서는 &lt;b&gt;무중단 배포가 필수&lt;/b&gt;이다.&lt;br /&gt;이 글에서는 MSA에서의 &lt;b&gt;CI/CD(지속적 통합&amp;middot;지속적 배포)&lt;/b&gt; 구조와 &lt;b&gt;무중단 배포 전략&lt;/b&gt;을 실전 중심으로 정리한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nGvjC/btsPxf0qTLk/lajboLXLf8z6iArkNGUFHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nGvjC/btsPxf0qTLk/lajboLXLf8z6iArkNGUFHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nGvjC/btsPxf0qTLk/lajboLXLf8z6iArkNGUFHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnGvjC%2FbtsPxf0qTLk%2FlajboLXLf8z6iArkNGUFHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;639&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;425&quot; data-start=&quot;399&quot; data-ke-size=&quot;size26&quot;&gt;✅ 왜 MSA에서는 CI/CD가 필수인가?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;564&quot; data-start=&quot;427&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;458&quot; data-start=&quot;427&quot;&gt;각 서비스가 독립적으로 개발되고 배포되어야 한다.&lt;/li&gt;
&lt;li data-end=&quot;497&quot; data-start=&quot;459&quot;&gt;변경 사항이 있을 때 빠르게 배포하고 롤백할 수 있어야 한다.&lt;/li&gt;
&lt;li data-end=&quot;535&quot; data-start=&quot;498&quot;&gt;사람의 개입 없이 &lt;b&gt;자동화된 배포 프로세스&lt;/b&gt;가 필요하다.&lt;/li&gt;
&lt;li data-end=&quot;564&quot; data-start=&quot;536&quot;&gt;배포 중에도 시스템은 안정적으로 동작해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;633&quot; data-start=&quot;566&quot; data-ke-size=&quot;size16&quot;&gt;CI/CD 없이 MSA를 운영하면 배포 과정이 &lt;b&gt;서비스 수만큼 곱절로 증가&lt;/b&gt;하며, 운영 비용이 기하급수적으로 커진다.&lt;/p&gt;
&lt;h2 data-end=&quot;648&quot; data-start=&quot;635&quot; data-ke-size=&quot;size26&quot;&gt;  CI/CD란?&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;826&quot; data-start=&quot;650&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;용어&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;748&quot; data-start=&quot;678&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;712&quot; data-start=&quot;678&quot;&gt;&lt;b&gt;CI (Continuous Integration)&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;748&quot; data-start=&quot;712&quot;&gt;코드 변경 시 자동으로 빌드, 테스트, 통합까지 수행한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;826&quot; data-start=&quot;749&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;791&quot; data-start=&quot;749&quot;&gt;&lt;b&gt;CD (Continuous Delivery/Deployment)&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;826&quot; data-start=&quot;791&quot;&gt;변경된 코드를 자동으로 검증하고 운영 환경까지 배포한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;MSA에서는 각 마이크로서비스에 대해 &lt;/span&gt;&lt;b&gt;독립적인 CI/CD 파이프라인&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;을 구축하는 것이 핵심이다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;912&quot; data-start=&quot;886&quot; data-ke-size=&quot;size26&quot;&gt; ️ 실무에서 자주 쓰는 CI/CD 도구&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1211&quot; data-start=&quot;914&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;범주&lt;/td&gt;
&lt;td&gt;도구&lt;/td&gt;
&lt;td&gt;특징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1025&quot; data-start=&quot;954&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;963&quot; data-start=&quot;954&quot;&gt;빌드/테스트&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1000&quot; data-start=&quot;963&quot;&gt;Jenkins, GitHub Actions, GitLab CI&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1025&quot; data-start=&quot;1000&quot;&gt;파이프라인 구성, 플러그인 생태계 풍부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1085&quot; data-start=&quot;1026&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1036&quot; data-start=&quot;1026&quot;&gt;아티팩트 관리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1063&quot; data-start=&quot;1036&quot;&gt;Nexus, JFrog Artifactory&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1085&quot; data-start=&quot;1063&quot;&gt;JAR, Docker 이미지 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1158&quot; data-start=&quot;1086&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1095&quot; data-start=&quot;1086&quot;&gt;배포 자동화&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1122&quot; data-start=&quot;1095&quot;&gt;Argo CD, Spinnaker, Helm&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1158&quot; data-start=&quot;1122&quot;&gt;GitOps, Canary, Blue-Green 배포 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1211&quot; data-start=&quot;1159&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1174&quot; data-start=&quot;1159&quot;&gt;클러스터 오케스트레이션&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1187&quot; data-start=&quot;1174&quot;&gt;Kubernetes&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1211&quot; data-start=&quot;1187&quot;&gt;롤링 업데이트, 헬스체크, 롤백 내장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1271&quot; data-start=&quot;1213&quot; data-ke-size=&quot;size16&quot;&gt;특히 최근에는 &lt;b&gt;Kubernetes + Argo CD + GitOps&lt;/b&gt; 조합이 빠르게 확산되고 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1287&quot; data-start=&quot;1273&quot; data-ke-size=&quot;size26&quot;&gt;  무중단 배포란?&lt;/h2&gt;
&lt;p data-end=&quot;1382&quot; data-start=&quot;1289&quot; data-ke-size=&quot;size16&quot;&gt;무중단 배포란 사용자가 서비스를 이용하는 중에도 &lt;b&gt;서비스의 중단 없이 새로운 버전으로 전환&lt;/b&gt;하는 배포 전략이다.&lt;br /&gt;MSA에서는 다음과 같은 전략이 주로 사용된다.&lt;/p&gt;
&lt;h3 data-end=&quot;1415&quot; data-start=&quot;1384&quot; data-ke-size=&quot;size23&quot;&gt;1. Rolling Update (롤링 업데이트)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1526&quot; data-start=&quot;1417&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1449&quot; data-start=&quot;1417&quot;&gt;인스턴스를 하나씩 교체하면서 새 버전으로 전환한다.&lt;/li&gt;
&lt;li data-end=&quot;1499&quot; data-start=&quot;1450&quot;&gt;전체 중 일부 인스턴스만 순차 교체하기 때문에 사용자는 다운타임을 느끼지 못한다.&lt;/li&gt;
&lt;li data-end=&quot;1526&quot; data-start=&quot;1500&quot;&gt;Kubernetes에서 기본 배포 전략이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1556&quot; data-start=&quot;1528&quot; data-ke-size=&quot;size23&quot;&gt;2. Blue-Green Deployment&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1654&quot; data-start=&quot;1558&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1596&quot; data-start=&quot;1558&quot;&gt;Blue(현재 버전)와 Green(새 버전)을 동시에 띄운 후&lt;/li&gt;
&lt;li data-end=&quot;1623&quot; data-start=&quot;1597&quot;&gt;트래픽 스위칭으로 전환 시점을 제어한다.&lt;/li&gt;
&lt;li data-end=&quot;1654&quot; data-start=&quot;1624&quot;&gt;장애 발생 시 빠르게 이전 버전으로 복귀 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1680&quot; data-start=&quot;1656&quot; data-ke-size=&quot;size23&quot;&gt;3. Canary Deployment&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1766&quot; data-start=&quot;1682&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1739&quot; data-start=&quot;1682&quot;&gt;전체 사용자 중 일부(5~10%)에게만 새 버전을 배포해 반응을 확인한 뒤 점진적으로 확산한다.&lt;/li&gt;
&lt;li data-end=&quot;1766&quot; data-start=&quot;1740&quot;&gt;오류나 성능 이슈를 사전에 차단할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1943&quot; data-start=&quot;1768&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;전략&lt;/td&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;단점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1857&quot; data-start=&quot;1808&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1818&quot; data-start=&quot;1808&quot;&gt;롤링 업데이트&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1835&quot; data-start=&quot;1818&quot;&gt;구성 간단, 다운타임 없음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1857&quot; data-start=&quot;1835&quot;&gt;장애 시 전체에 영향 줄 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1903&quot; data-start=&quot;1858&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1866&quot; data-start=&quot;1858&quot;&gt;블루-그린&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1887&quot; data-start=&quot;1866&quot;&gt;빠른 롤백 가능, 완전 분리 배포&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1903&quot; data-start=&quot;1887&quot;&gt;인프라 자원 이중 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1943&quot; data-start=&quot;1904&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1910&quot; data-start=&quot;1904&quot;&gt;카나리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1926&quot; data-start=&quot;1910&quot;&gt;품질 검증 후 전체 배포&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1943&quot; data-start=&quot;1926&quot;&gt;트래픽 라우팅 설정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1987&quot; data-start=&quot;1945&quot; data-ke-size=&quot;size26&quot;&gt;  Spring Boot + Docker + Kubernetes 예시&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2144&quot; data-start=&quot;1989&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2024&quot; data-start=&quot;1989&quot;&gt;&lt;b&gt;GitHub Action으로 Push 감지 후 빌드&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2059&quot; data-start=&quot;2025&quot;&gt;&lt;b&gt;Docker 이미지 생성 및 레지스트리에 Push&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2106&quot; data-start=&quot;2060&quot;&gt;&lt;b&gt;Kubernetes의 Deployment 오브젝트가 롤링 업데이트 실행&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2144&quot; data-start=&quot;2107&quot;&gt;&lt;b&gt;서비스 무중단 상태 유지, 헬스체크 실패 시 자동 롤백&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-end=&quot;2175&quot; data-start=&quot;2146&quot; data-ke-size=&quot;size23&quot;&gt;Rolling 업데이트 예시 (kubectl)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753321129082&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl set image deployment/user-service user-service=image:v2
kubectl rollout status deployment/user-service&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2314&quot; data-start=&quot;2301&quot; data-ke-size=&quot;size26&quot;&gt;  실무 적용 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2547&quot; data-start=&quot;2316&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2357&quot; data-start=&quot;2316&quot;&gt;모든 서비스에 대해 &lt;b&gt;독립된 배포 파이프라인 구축&lt;/b&gt;이 핵심이다.&lt;/li&gt;
&lt;li data-end=&quot;2407&quot; data-start=&quot;2358&quot;&gt;마이크로서비스마다 배포 주기가 다르므로 &lt;b&gt;개별 배포와 롤백이 가능해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2476&quot; data-start=&quot;2408&quot;&gt;배포 시 사용자에게 영향을 주지 않도록 &lt;b&gt;Liveness/Readiness Probe&lt;/b&gt;를 반드시 설정해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;2547&quot; data-start=&quot;2477&quot;&gt;로그 수집(ELK/EFK)과 모니터링(Prometheus, Grafana)을 연동해 배포 후 상태를 실시간 추적해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2556&quot; data-start=&quot;2549&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;2756&quot; data-start=&quot;2558&quot; data-ke-size=&quot;size16&quot;&gt;MSA에서 CI/CD는 &lt;b&gt;개발과 운영을 연결하는 핵심 자동화 시스템&lt;/b&gt;이다.&lt;br /&gt;무중단 배포 전략은 MSA의 빠른 개발 사이클과 서비스 안정성을 동시에 만족시키는 방법이다.&lt;br /&gt;롤링 업데이트, 블루-그린, 카나리 배포를 상황에 맞게 선택하고,&lt;br /&gt;GitOps 기반 자동화와 Kubernetes 연동을 통해 &lt;b&gt;진짜 무중단 배포 환경을 구축&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;h2 data-end=&quot;2773&quot; data-start=&quot;2758&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3102&quot; data-start=&quot;2775&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2837&quot; data-start=&quot;2775&quot;&gt;&lt;a data-end=&quot;2835&quot; data-start=&quot;2777&quot;&gt;GitHub Actions 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;2950&quot; data-start=&quot;2838&quot;&gt;&lt;a data-end=&quot;2948&quot; data-start=&quot;2840&quot;&gt;Kubernetes Rolling Update 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3013&quot; data-start=&quot;2951&quot;&gt;&lt;a data-end=&quot;3011&quot; data-start=&quot;2953&quot;&gt;Argo CD 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3102&quot; data-start=&quot;3014&quot;&gt;&lt;a data-end=&quot;3102&quot; data-start=&quot;3016&quot;&gt;Canary 배포 가이드 - Istio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3226&quot; data-start=&quot;3128&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>bluegreen</category>
      <category>CanaryDeployment</category>
      <category>ci_cd</category>
      <category>GitOps</category>
      <category>Kubernetes배포</category>
      <category>MSA</category>
      <category>RollingUpdate</category>
      <category>Spring배포자동화</category>
      <category>마이크로서비스배포</category>
      <category>무중단배포</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1062</guid>
      <comments>https://monkeybusiness.tistory.com/1062#entry1062comment</comments>
      <pubDate>Thu, 24 Jul 2025 11:39:30 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] JWT와 OAuth2로 인증 처리하는 방법</title>
      <link>https://monkeybusiness.tistory.com/1061</link>
      <description>&lt;p data-end=&quot;532&quot; data-start=&quot;192&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)에서 인증(Authentication)과 인가(Authorization)는 단일 애플리케이션보다 훨씬 복잡하다.&lt;br /&gt;서비스가 분리되어 있으므로 사용자의 로그인 정보를 각 서비스에 개별적으로 전달하고 관리하는 방식은 현실적으로 불가능하다.&lt;br /&gt;이를 해결하기 위해 등장한 대표적인 인증 방식이 &lt;b&gt;OAuth2.0&lt;/b&gt;, &lt;b&gt;OpenID Connect&lt;/b&gt;, 그리고 &lt;b&gt;JWT(Json Web Token)&lt;/b&gt; 기반 인증이다.&lt;br /&gt;이번 글에서는 Spring Security 환경에서 JWT와 OAuth2를 활용해 &lt;b&gt;확장성과 보안성을 동시에 갖춘 인증 체계&lt;/b&gt;를 설계하는 방법을 설명한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxBLyr/btsPv46WhHD/8Ixvk0GKVDg3GhB4ZuAcgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxBLyr/btsPv46WhHD/8Ixvk0GKVDg3GhB4ZuAcgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxBLyr/btsPv46WhHD/8Ixvk0GKVDg3GhB4ZuAcgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxBLyr%2FbtsPv46WhHD%2F8Ixvk0GKVDg3GhB4ZuAcgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;559&quot; data-start=&quot;534&quot; data-ke-size=&quot;size26&quot;&gt;✅ 마이크로서비스에서 인증이 어려운 이유&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;795&quot; data-start=&quot;561&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;623&quot; data-start=&quot;561&quot;&gt;모든 서비스가 독립되어 있어 각자 인증/인가를 구현하면 &lt;b&gt;중복 로직&lt;/b&gt;과 &lt;b&gt;보안 취약점&lt;/b&gt;이 생긴다.&lt;/li&gt;
&lt;li data-end=&quot;664&quot; data-start=&quot;624&quot;&gt;인증 로직이 변경되면 여러 서비스에 &lt;b&gt;동시 배포&lt;/b&gt;가 필요하다.&lt;/li&gt;
&lt;li data-end=&quot;730&quot; data-start=&quot;665&quot;&gt;프론트엔드 &amp;rarr; Gateway &amp;rarr; 내부 서비스로 이어지는 흐름에서 &lt;b&gt;인증 토큰을 공유하는 체계&lt;/b&gt;가 필요하다.&lt;/li&gt;
&lt;li data-end=&quot;795&quot; data-start=&quot;731&quot;&gt;OAuth2처럼 외부 인증 제공자(Google, Kakao 등)와 연동하려면 &lt;b&gt;중앙 인증 서버&lt;/b&gt;가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;824&quot; data-start=&quot;797&quot; data-ke-size=&quot;size26&quot;&gt;  JWT(Json Web Token)란?&lt;/h2&gt;
&lt;p data-end=&quot;941&quot; data-start=&quot;826&quot; data-ke-size=&quot;size16&quot;&gt;JWT는 인증 정보를 JSON 포맷으로 담아 &lt;b&gt;디지털 서명된 토큰&lt;/b&gt;으로 만들어 전달하는 방식이다.&lt;br /&gt;토큰은 일반적으로 헤더(Header), 내용(Payload), 서명(Signature)으로 구성된다.&lt;/p&gt;
&lt;h3 data-end=&quot;956&quot; data-start=&quot;943&quot; data-ke-size=&quot;size23&quot;&gt;  JWT 구조&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUnNVI/btsPwYq5a5E/zMDpNjcxFl8MkA66vAjFa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUnNVI/btsPwYq5a5E/zMDpNjcxFl8MkA66vAjFa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUnNVI/btsPwYq5a5E/zMDpNjcxFl8MkA66vAjFa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUnNVI%2FbtsPwYq5a5E%2FzMDpNjcxFl8MkA66vAjFa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;171&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1137&quot; data-start=&quot;1027&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1061&quot; data-start=&quot;1027&quot;&gt;&lt;b&gt;Header&lt;/b&gt;: 알고리즘 정보 (예: HS256)&lt;/li&gt;
&lt;li data-end=&quot;1106&quot; data-start=&quot;1062&quot;&gt;&lt;b&gt;Payload&lt;/b&gt;: 사용자 정보, 권한, 만료 시간 등의 Claims&lt;/li&gt;
&lt;li data-end=&quot;1137&quot; data-start=&quot;1107&quot;&gt;&lt;b&gt;Signature&lt;/b&gt;: 비밀 키로 암호화된 서명&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1245&quot; data-start=&quot;1139&quot; data-ke-size=&quot;size16&quot;&gt;JWT는 &lt;b&gt;토큰 자체에 정보를 담기 때문에 서버 상태를 유지하지 않아도 된다.&lt;/b&gt;&lt;br /&gt;즉, &lt;b&gt;Stateless 인증&lt;/b&gt;에 적합하며, 모든 마이크로서비스에서 동일한 방식으로 검증 가능하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1259&quot; data-start=&quot;1247&quot; data-ke-size=&quot;size23&quot;&gt;✅ JWT 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1357&quot; data-start=&quot;1261&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1311&quot; data-start=&quot;1261&quot;&gt;중앙 인증 서버를 거쳐 받은 토큰만 있으면 &lt;b&gt;각 서비스가 독립적으로 검증 가능&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1330&quot; data-start=&quot;1312&quot;&gt;별도의 세션 저장소 불필요&lt;/li&gt;
&lt;li data-end=&quot;1357&quot; data-start=&quot;1331&quot;&gt;RESTful API에 이상적으로 적용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1371&quot; data-start=&quot;1359&quot; data-ke-size=&quot;size23&quot;&gt;❌ JWT 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1490&quot; data-start=&quot;1373&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1414&quot; data-start=&quot;1373&quot;&gt;토큰 탈취 시 무력화가 어렵다 (재발급 또는 만료 시간 조정 필요)&lt;/li&gt;
&lt;li data-end=&quot;1442&quot; data-start=&quot;1415&quot;&gt;토큰 길이가 길어 네트워크 비용 증가 가능&lt;/li&gt;
&lt;li data-end=&quot;1490&quot; data-start=&quot;1443&quot;&gt;서버에서 임의로 토큰을 만료시키기 어려움 (단점 보완 위해 블랙리스트 사용 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1506&quot; data-start=&quot;1492&quot; data-ke-size=&quot;size26&quot;&gt;  OAuth2란?&lt;/h2&gt;
&lt;p data-end=&quot;1650&quot; data-start=&quot;1508&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OAuth2.0&lt;/b&gt;은 사용자 인증을 제3자 인증 서버에 위임하고, 엑세스 토큰(access token)을 발급받아 보호된 자원에 접근하는 표준 프로토콜이다.&lt;br /&gt;Google, Facebook, Kakao 등 외부 로그인 연동이 대표적인 예이다.&lt;/p&gt;
&lt;h3 data-end=&quot;1671&quot; data-start=&quot;1652&quot; data-ke-size=&quot;size23&quot;&gt;  OAuth2 흐름 요약&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1792&quot; data-start=&quot;1673&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1689&quot; data-start=&quot;1673&quot;&gt;사용자가 로그인 시도&lt;/li&gt;
&lt;li data-end=&quot;1722&quot; data-start=&quot;1690&quot;&gt;인증 서버가 인증 후 Access Token 발급&lt;/li&gt;
&lt;li data-end=&quot;1764&quot; data-start=&quot;1723&quot;&gt;클라이언트는 이 토큰을 가지고 Resource Server에 요청&lt;/li&gt;
&lt;li data-end=&quot;1792&quot; data-start=&quot;1765&quot;&gt;리소스 서버는 토큰의 유효성을 검증하여 응답&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1868&quot; data-start=&quot;1794&quot; data-ke-size=&quot;size16&quot;&gt;Spring Security에서는 spring-security-oauth2를 통해 OAuth2 인증/인가를 쉽게 구현할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;1885&quot; data-start=&quot;1870&quot; data-ke-size=&quot;size23&quot;&gt;✅ OAuth2 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1964&quot; data-start=&quot;1887&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1906&quot; data-start=&quot;1887&quot;&gt;외부 로그인 연동이 용이하다&lt;/li&gt;
&lt;li data-end=&quot;1941&quot; data-start=&quot;1907&quot;&gt;인증 서버와 리소스 서버 분리 가능 (보안/운영 분리)&lt;/li&gt;
&lt;li data-end=&quot;1964&quot; data-start=&quot;1942&quot;&gt;다양한 인증 방식을 유연하게 지원한다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2004&quot; data-start=&quot;1966&quot; data-ke-size=&quot;size26&quot;&gt;  JWT + OAuth2 + OpenID Connect 조합&lt;/h2&gt;
&lt;p data-end=&quot;2127&quot; data-start=&quot;2006&quot; data-ke-size=&quot;size16&quot;&gt;실무에서는 OAuth2 인증을 통해 &lt;b&gt;Access Token을 JWT 형식으로 발급&lt;/b&gt;받는 방식이 일반적이다.&lt;br /&gt;여기에 OpenID Connect를 함께 사용하면 사용자 정보 조회 및 로그인 세션 유지가 가능하다.&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2239&quot; data-start=&quot;2129&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구성 요소&lt;/td&gt;
&lt;td&gt;역할&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2186&quot; data-start=&quot;2164&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2173&quot; data-start=&quot;2164&quot;&gt;OAuth2&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2186&quot; data-start=&quot;2173&quot;&gt;인증 흐름 표준화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2220&quot; data-start=&quot;2187&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2204&quot; data-start=&quot;2187&quot;&gt;OpenID Connect&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2220&quot; data-start=&quot;2204&quot;&gt;사용자 식별 정보 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2239&quot; data-start=&quot;2221&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2227&quot; data-start=&quot;2221&quot;&gt;JWT&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2239&quot; data-start=&quot;2227&quot;&gt;인증 토큰 포맷&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2272&quot; data-start=&quot;2241&quot; data-ke-size=&quot;size26&quot;&gt; ️ Spring Security에서의 구현 방식&lt;/h2&gt;
&lt;h3 data-end=&quot;2287&quot; data-start=&quot;2274&quot; data-ke-size=&quot;size23&quot;&gt;1. 의존성 추가&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753320628490&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-security'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2485&quot; data-start=&quot;2460&quot; data-ke-size=&quot;size23&quot;&gt;2. application.yml 설정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753320640554&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: http://auth-server/.well-known/jwks.json&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2646&quot; data-start=&quot;2631&quot; data-ke-size=&quot;size23&quot;&gt;3. 인증 처리 예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753320648882&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@GetMapping(&quot;/me&quot;)
public ResponseEntity&amp;lt;String&amp;gt; getProfile(@AuthenticationPrincipal Jwt jwt) {
    return ResponseEntity.ok(jwt.getSubject());
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2853&quot; data-start=&quot;2807&quot; data-ke-size=&quot;size16&quot;&gt;모든 마이크로서비스는 JWT의 유효성만 검증하면 인증된 사용자임을 신뢰할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;2881&quot; data-start=&quot;2855&quot; data-ke-size=&quot;size26&quot;&gt;  API Gateway + JWT 전략&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3027&quot; data-start=&quot;2883&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2912&quot; data-start=&quot;2883&quot;&gt;사용자가 로그인하면 인증 서버에서 JWT 발급&lt;/li&gt;
&lt;li data-end=&quot;2953&quot; data-start=&quot;2913&quot;&gt;프론트엔드는 JWT를 Authorization 헤더에 실어서 요청&lt;/li&gt;
&lt;li data-end=&quot;2996&quot; data-start=&quot;2954&quot;&gt;API Gateway는 JWT를 검증하고, 내부 마이크로서비스로 전달&lt;/li&gt;
&lt;li data-end=&quot;3027&quot; data-start=&quot;2997&quot;&gt;마이크로서비스는 토큰만으로 사용자 정보를 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKZgMJ/btsPv1PR5Fz/gwq74gTsuOE9c0OHWDckK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKZgMJ/btsPv1PR5Fz/gwq74gTsuOE9c0OHWDckK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKZgMJ/btsPv1PR5Fz/gwq74gTsuOE9c0OHWDckK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKZgMJ%2FbtsPv1PR5Fz%2Fgwq74gTsuOE9c0OHWDckK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;57&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;3121&quot; data-start=&quot;3114&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3339&quot; data-start=&quot;3123&quot; data-ke-size=&quot;size16&quot;&gt;MSA에서 인증 시스템을 설계할 때는 &lt;b&gt;분산 구조에 맞는 확장성과 보안성&lt;/b&gt;이 중요하다.&lt;br /&gt;JWT는 &lt;b&gt;Stateless 인증 방식&lt;/b&gt;으로 마이크로서비스에 적합하며, OAuth2는 &lt;b&gt;권한 위임과 외부 인증 연동&lt;/b&gt;에 강점을 가진다.&lt;br /&gt;두 기술을 결합하여 인증 서버와 리소스 서버를 분리하고, &lt;b&gt;토큰 기반 인증 구조&lt;/b&gt;를 정립하면&lt;br /&gt;운영 효율성과 보안성을 모두 확보할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;3356&quot; data-start=&quot;3341&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3613&quot; data-start=&quot;3358&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3446&quot; data-start=&quot;3358&quot;&gt;&lt;a data-end=&quot;3444&quot; data-start=&quot;3360&quot;&gt;Spring Security 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3518&quot; data-start=&quot;3447&quot;&gt;&lt;a data-end=&quot;3516&quot; data-start=&quot;3449&quot;&gt;JWT 공식 스펙 RFC 7519&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3562&quot; data-start=&quot;3519&quot;&gt;&lt;a data-end=&quot;3560&quot; data-start=&quot;3521&quot;&gt;OAuth2.0 스펙 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3613&quot; data-start=&quot;3563&quot;&gt;&lt;a data-end=&quot;3613&quot; data-start=&quot;3565&quot;&gt;OpenID Connect 소개&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3729&quot; data-start=&quot;3639&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>accesstoken</category>
      <category>JWT</category>
      <category>MSA</category>
      <category>MSA인증구조</category>
      <category>oauth2</category>
      <category>openidconnect</category>
      <category>SpringSecurity</category>
      <category>Stateless인증</category>
      <category>마이크로서비스보안</category>
      <category>토큰인증</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1061</guid>
      <comments>https://monkeybusiness.tistory.com/1061#entry1061comment</comments>
      <pubDate>Thu, 24 Jul 2025 10:36:59 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] Kafka vs RabbitMQ: 메시지 기반 아키텍처 완전정복</title>
      <link>https://monkeybusiness.tistory.com/1060</link>
      <description>&lt;p data-end=&quot;466&quot; data-start=&quot;218&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 서비스 간의 결합도를 낮추기 위해 &lt;b&gt;비동기 메시지 기반 통신을 적극 활용&lt;/b&gt;한다.&lt;br /&gt;그 중심에 있는 것이 바로 &lt;b&gt;메시지 브로커(Message Broker)&lt;/b&gt;이다.&lt;br /&gt;그중 가장 많이 사용되는 두 가지 솔루션이 &lt;b&gt;Apache Kafka&lt;/b&gt;와 &lt;b&gt;RabbitMQ&lt;/b&gt;이다.&lt;br /&gt;이번 글에서는 Kafka와 RabbitMQ의 구조, 차이점, 적용 사례를 비교하고, MSA에 어떻게 활용할 수 있는지를 정리한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0POYV/btsPu9mEfnS/T645VI4emOZqrEBWvI3ZNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0POYV/btsPu9mEfnS/T645VI4emOZqrEBWvI3ZNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0POYV/btsPu9mEfnS/T645VI4emOZqrEBWvI3ZNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0POYV%2FbtsPu9mEfnS%2FT645VI4emOZqrEBWvI3ZNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;486&quot; data-start=&quot;468&quot; data-ke-size=&quot;size26&quot;&gt;✅ 메시지 기반 아키텍처란?&lt;/h2&gt;
&lt;p data-end=&quot;610&quot; data-start=&quot;488&quot; data-ke-size=&quot;size16&quot;&gt;메시지 기반 아키텍처는 서비스를 직접 호출하는 것이 아니라 &lt;b&gt;이벤트나 메시지를 발행하고, 필요한 서비스가 이를 구독(Subscribe)&lt;/b&gt; 하여 처리하는 구조이다.&lt;br /&gt;이 방식은 다음과 같은 MSA의 과제를 해결한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;685&quot; data-start=&quot;612&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;631&quot; data-start=&quot;612&quot;&gt;서비스 간 강한 결합을 제거&lt;/li&gt;
&lt;li data-end=&quot;655&quot; data-start=&quot;632&quot;&gt;비동기 처리를 통한 응답 속도 향상&lt;/li&gt;
&lt;li data-end=&quot;670&quot; data-start=&quot;656&quot;&gt;장애 전파를 최소화&lt;/li&gt;
&lt;li data-end=&quot;685&quot; data-start=&quot;671&quot;&gt;이벤트 기반 확장 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;753&quot; data-start=&quot;687&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 결제 완료 이벤트가 발생하면 주문 서비스, 배송 서비스, 알림 서비스가 이를 구독하고 각자 처리할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;775&quot; data-start=&quot;755&quot; data-ke-size=&quot;size26&quot;&gt;  Apache Kafka란?&lt;/h2&gt;
&lt;p data-end=&quot;894&quot; data-start=&quot;777&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Kafka&lt;/b&gt;는 대용량 데이터 처리에 최적화된 &lt;b&gt;분산 스트리밍 플랫폼&lt;/b&gt;이다.&lt;br /&gt;기본적으로 메시지를 &lt;b&gt;로그 형태로 저장&lt;/b&gt;하고, 소비자는 자신이 필요한 메시지를 &lt;b&gt;순서대로 읽어가는 구조&lt;/b&gt;를 가진다.&lt;/p&gt;
&lt;h3 data-end=&quot;908&quot; data-start=&quot;896&quot; data-ke-size=&quot;size23&quot;&gt;  주요 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1049&quot; data-start=&quot;910&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;948&quot; data-start=&quot;910&quot;&gt;&lt;b&gt;고속 처리&lt;/b&gt;: 초당 수십만 건 이상의 메시지를 처리 가능&lt;/li&gt;
&lt;li data-end=&quot;977&quot; data-start=&quot;949&quot;&gt;&lt;b&gt;내구성&lt;/b&gt;: 디스크에 메시지를 영구 저장&lt;/li&gt;
&lt;li data-end=&quot;1011&quot; data-start=&quot;978&quot;&gt;&lt;b&gt;스케일 아웃&lt;/b&gt;: 브로커, 파티션 단위 확장 용이&lt;/li&gt;
&lt;li data-end=&quot;1049&quot; data-start=&quot;1012&quot;&gt;&lt;b&gt;구독 기반 소비&lt;/b&gt;: 다수의 컨슈머 그룹이 병렬로 처리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1070&quot; data-start=&quot;1051&quot; data-ke-size=&quot;size23&quot;&gt;✅ Kafka에 적합한 상황&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1150&quot; data-start=&quot;1072&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1090&quot; data-start=&quot;1072&quot;&gt;이벤트 소싱 기반 아키텍처&lt;/li&gt;
&lt;li data-end=&quot;1108&quot; data-start=&quot;1091&quot;&gt;대규모 실시간 로그 수집&lt;/li&gt;
&lt;li data-end=&quot;1125&quot; data-start=&quot;1109&quot;&gt;데이터 파이프라인 구축&lt;/li&gt;
&lt;li data-end=&quot;1150&quot; data-start=&quot;1126&quot;&gt;다수의 수신자가 동일 이벤트를 처리할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1168&quot; data-start=&quot;1152&quot; data-ke-size=&quot;size26&quot;&gt;  RabbitMQ란?&lt;/h2&gt;
&lt;p data-end=&quot;1291&quot; data-start=&quot;1170&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RabbitMQ&lt;/b&gt;는 고전적인 메시지 브로커로, &lt;b&gt;AMQP 프로토콜 기반의 메시지 큐 시스템&lt;/b&gt;이다.&lt;br /&gt;발신자는 메시지를 Exchange에 전달하고, Exchange는 바인딩된 Queue로 메시지를 라우팅한다.&lt;/p&gt;
&lt;h3 data-end=&quot;1305&quot; data-start=&quot;1293&quot; data-ke-size=&quot;size23&quot;&gt;  주요 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1444&quot; data-start=&quot;1307&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1361&quot; data-start=&quot;1307&quot;&gt;&lt;b&gt;유연한 라우팅&lt;/b&gt;: Direct, Topic, Fanout 등 다양한 메시지 전달 방식&lt;/li&gt;
&lt;li data-end=&quot;1408&quot; data-start=&quot;1362&quot;&gt;&lt;b&gt;확실한 전달 보장&lt;/b&gt;: Acknowledge, 재전송, 지연 큐 등 제공&lt;/li&gt;
&lt;li data-end=&quot;1444&quot; data-start=&quot;1409&quot;&gt;&lt;b&gt;경량 서비스에 적합&lt;/b&gt;: 설정이 간단하고 빠른 구축 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1468&quot; data-start=&quot;1446&quot; data-ke-size=&quot;size23&quot;&gt;✅ RabbitMQ에 적합한 상황&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1575&quot; data-start=&quot;1470&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1499&quot; data-start=&quot;1470&quot;&gt;요청 &amp;rarr; 응답 중심의 &lt;b&gt;비동기 작업 처리&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1524&quot; data-start=&quot;1500&quot;&gt;우선순위 큐, 지연 큐가 필요한 환경&lt;/li&gt;
&lt;li data-end=&quot;1551&quot; data-start=&quot;1525&quot;&gt;빠르게 메시지를 받아 단기 저장 후 소비&lt;/li&gt;
&lt;li data-end=&quot;1575&quot; data-start=&quot;1552&quot;&gt;소규모 시스템에서의 간단한 비동기 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1603&quot; data-start=&quot;1577&quot; data-ke-size=&quot;size26&quot;&gt;  Kafka vs RabbitMQ 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1986&quot; data-start=&quot;1605&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;Kafka&lt;/td&gt;
&lt;td&gt;RabbitMQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1686&quot; data-start=&quot;1659&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1664&quot; data-start=&quot;1659&quot;&gt;구조&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1677&quot; data-start=&quot;1664&quot;&gt;로그 기반 스트리밍&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1686&quot; data-start=&quot;1677&quot;&gt;메시지 큐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1732&quot; data-start=&quot;1687&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1696&quot; data-start=&quot;1687&quot;&gt;메시지 저장&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1712&quot; data-start=&quot;1696&quot;&gt;디스크 기반, 영구 보존&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1732&quot; data-start=&quot;1712&quot;&gt;큐 기반, 소비 후 삭제 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1764&quot; data-start=&quot;1733&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1739&quot; data-start=&quot;1733&quot;&gt;처리량&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1750&quot; data-start=&quot;1739&quot;&gt;초당 수십만 건&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1764&quot; data-start=&quot;1750&quot;&gt;초당 수천~수만 건&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1806&quot; data-start=&quot;1765&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1774&quot; data-start=&quot;1765&quot;&gt;메시지 순서&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1788&quot; data-start=&quot;1774&quot;&gt;보장 (파티션 기준)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1806&quot; data-start=&quot;1788&quot;&gt;큐에 따라 순서 보장 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1853&quot; data-start=&quot;1807&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1816&quot; data-start=&quot;1807&quot;&gt;소비자 모델&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1834&quot; data-start=&quot;1816&quot;&gt;Pull 기반, 오프셋 저장&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1853&quot; data-start=&quot;1834&quot;&gt;Push 기반, ACK 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1909&quot; data-start=&quot;1854&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1860&quot; data-start=&quot;1854&quot;&gt;라우팅&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1877&quot; data-start=&quot;1860&quot;&gt;제한적 (Topic 기준)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1909&quot; data-start=&quot;1877&quot;&gt;고급 라우팅 제공 (Exchange + Queue)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1943&quot; data-start=&quot;1910&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1920&quot; data-start=&quot;1910&quot;&gt;설치 및 운영&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1932&quot; data-start=&quot;1920&quot;&gt;상대적으로 복잡함&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1943&quot; data-start=&quot;1932&quot;&gt;비교적 간단함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1986&quot; data-start=&quot;1944&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1951&quot; data-start=&quot;1944&quot;&gt;사용 예&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1966&quot; data-start=&quot;1951&quot;&gt;로그, 이벤트 스트리밍&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1986&quot; data-start=&quot;1966&quot;&gt;백그라운드 작업, 알림 큐 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2005&quot; data-start=&quot;1988&quot; data-ke-size=&quot;size26&quot;&gt;  실무에서의 선택 기준&lt;/h2&gt;
&lt;h3 data-end=&quot;2026&quot; data-start=&quot;2007&quot; data-ke-size=&quot;size23&quot;&gt;Kafka를 선택해야 할 때&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2135&quot; data-start=&quot;2028&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2073&quot; data-start=&quot;2028&quot;&gt;&lt;b&gt;대규모 데이터 처리&lt;/b&gt;가 필요하거나, &lt;b&gt;이벤트 저장이 중요&lt;/b&gt;한 경우&lt;/li&gt;
&lt;li data-end=&quot;2111&quot; data-start=&quot;2074&quot;&gt;여러 서비스가 &lt;b&gt;동일 이벤트를 병렬 처리&lt;/b&gt;해야 하는 경우&lt;/li&gt;
&lt;li data-end=&quot;2135&quot; data-start=&quot;2112&quot;&gt;실시간 분석, 데이터 스트림 처리 목적&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2159&quot; data-start=&quot;2137&quot; data-ke-size=&quot;size23&quot;&gt;RabbitMQ를 선택해야 할 때&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2269&quot; data-start=&quot;2161&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2198&quot; data-start=&quot;2161&quot;&gt;메시지 &lt;b&gt;즉시 처리와 응답&lt;/b&gt;이 중요한 백엔드 비동기 로직&lt;/li&gt;
&lt;li data-end=&quot;2234&quot; data-start=&quot;2199&quot;&gt;복잡한 라우팅 또는 지연 큐, 우선순위 큐가 필요한 경우&lt;/li&gt;
&lt;li data-end=&quot;2269&quot; data-start=&quot;2235&quot;&gt;설정이 간단하고 &lt;b&gt;빠른 구축이 필요한 소규모 프로젝트&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2298&quot; data-start=&quot;2271&quot; data-ke-size=&quot;size26&quot;&gt; ️ Spring Boot에서의 통합 방법&lt;/h2&gt;
&lt;h3 data-end=&quot;2315&quot; data-start=&quot;2300&quot; data-ke-size=&quot;size23&quot;&gt;Kafka 연동 예시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;yml 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753249691809&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: my-service&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753249709497&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@KafkaListener(topics = &quot;order-events&quot;)
public void handleOrder(String message) {
    // 메시지 처리 로직
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2558&quot; data-start=&quot;2540&quot; data-ke-size=&quot;size23&quot;&gt;RabbitMQ 연동 예시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;yml 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753249719209&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  rabbitmq:
    host: localhost
    port: 5672&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753249773033&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RabbitListener(queues = &quot;order-queue&quot;)
public void consumeOrder(String message) {
    // 메시지 처리 로직
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2750&quot; data-start=&quot;2743&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3027&quot; data-start=&quot;2752&quot; data-ke-size=&quot;size16&quot;&gt;Kafka와 RabbitMQ는 각각의 목적과 강점을 가진 메시지 브로커이다.&lt;br /&gt;Kafka는 &lt;b&gt;대규모 이벤트 스트리밍&lt;/b&gt;, &lt;b&gt;로그 저장&lt;/b&gt;, &lt;b&gt;복수 소비자 처리&lt;/b&gt;에 적합하며,&lt;br /&gt;RabbitMQ는 &lt;b&gt;백그라운드 작업 처리&lt;/b&gt;, &lt;b&gt;큐 기반 비동기 통신&lt;/b&gt;, &lt;b&gt;우선순위 메시징&lt;/b&gt;에 유리하다.&lt;br /&gt;MSA 시스템에서는 이 두 가지를 &lt;b&gt;용도별로 병행 사용하는 경우도 많다.&lt;/b&gt;&lt;br /&gt;자신의 서비스 환경에 맞게 &lt;b&gt;기능, 성능, 운영 복잡도 등을 고려하여 적절히 선택&lt;/b&gt;하는 것이 중요하다.&lt;/p&gt;
&lt;h2 data-end=&quot;3044&quot; data-start=&quot;3029&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3346&quot; data-start=&quot;3046&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3111&quot; data-start=&quot;3046&quot;&gt;&lt;a data-end=&quot;3109&quot; data-start=&quot;3048&quot;&gt;Apache Kafka 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3160&quot; data-start=&quot;3112&quot;&gt;&lt;a data-end=&quot;3158&quot; data-start=&quot;3114&quot;&gt;RabbitMQ 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3256&quot; data-start=&quot;3161&quot;&gt;&lt;a data-end=&quot;3254&quot; data-start=&quot;3163&quot;&gt;Spring for Apache Kafka&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3346&quot; data-start=&quot;3257&quot;&gt;&lt;a data-end=&quot;3346&quot; data-start=&quot;3259&quot;&gt;Spring AMQP RabbitMQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3457&quot; data-start=&quot;3372&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>Kafka</category>
      <category>MSA</category>
      <category>MSA메시징</category>
      <category>RabbitMQ</category>
      <category>springkafka</category>
      <category>springrabbitmq</category>
      <category>마이크로서비스통신</category>
      <category>메시지브로커</category>
      <category>비동기아키텍처</category>
      <category>이벤트기반설계</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1060</guid>
      <comments>https://monkeybusiness.tistory.com/1060#entry1060comment</comments>
      <pubDate>Wed, 23 Jul 2025 23:52:27 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] Spring Cloud Config와 Vault로 설정 통합 관리</title>
      <link>https://monkeybusiness.tistory.com/1059</link>
      <description>&lt;p data-end=&quot;523&quot; data-start=&quot;237&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 서비스가 많아질수록 &lt;b&gt;설정(Configuration)의 복잡도와 보안 위험이 급격히 증가&lt;/b&gt;한다.&lt;br /&gt;각 서비스의 application.yml 파일이 중복되고, 데이터베이스 정보나 API 키 같은 민감한 정보가 소스코드에 포함되는 상황도 발생한다.&lt;br /&gt;이 문제를 해결하기 위해 등장한 도구가 바로 &lt;b&gt;Spring Cloud Config&lt;/b&gt;와 &lt;b&gt;Vault&lt;/b&gt;이다.&lt;br /&gt;이 두 가지를 결합하면 &lt;b&gt;설정은 중앙에서 관리하고, 민감 정보는 안전하게 분리하여 운영&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q0ipD/btsPuFTVPKb/BYPDb5wC20sb5xpA9fh7g0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q0ipD/btsPuFTVPKb/BYPDb5wC20sb5xpA9fh7g0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q0ipD/btsPuFTVPKb/BYPDb5wC20sb5xpA9fh7g0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq0ipD%2FbtsPuFTVPKb%2FBYPDb5wC20sb5xpA9fh7g0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;545&quot; data-start=&quot;525&quot; data-ke-size=&quot;size26&quot;&gt;✅ 왜 설정 중앙화가 필요한가?&lt;/h2&gt;
&lt;p data-end=&quot;623&quot; data-start=&quot;547&quot; data-ke-size=&quot;size16&quot;&gt;MSA 환경에서는 서비스가 수십 개 이상으로 분리된다.&lt;br /&gt;각 서비스의 설정 파일이 개별적으로 존재할 경우 다음과 같은 문제가 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;742&quot; data-start=&quot;625&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;652&quot; data-start=&quot;625&quot;&gt;설정 값 변경 시 모든 서비스 재배포 필요&lt;/li&gt;
&lt;li data-end=&quot;694&quot; data-start=&quot;653&quot;&gt;환경별(dev, staging, prod) 설정 파일 유지가 어려움&lt;/li&gt;
&lt;li data-end=&quot;718&quot; data-start=&quot;695&quot;&gt;운영 중 민감 정보 노출 위험 증가&lt;/li&gt;
&lt;li data-end=&quot;742&quot; data-start=&quot;719&quot;&gt;설정 누락 또는 오타로 인한 장애 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;828&quot; data-start=&quot;744&quot; data-ke-size=&quot;size16&quot;&gt;이를 방지하려면 &lt;b&gt;설정을 Git 또는 Vault에 중앙 집중화하고, 각 서비스는 부팅 시점에 해당 설정을 동적으로 가져오는 구조&lt;/b&gt;로 구성해야 한다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;857&quot; data-start=&quot;830&quot; data-ke-size=&quot;size26&quot;&gt;  Spring Cloud Config란?&lt;/h2&gt;
&lt;p data-end=&quot;1073&quot; data-start=&quot;859&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring Cloud Config&lt;/b&gt;는 Git 또는 파일 시스템에 저장된 설정 값을 외부 Config Server를 통해 &lt;b&gt;서비스에 실시간으로 배포&lt;/b&gt;하는 구조이다.&lt;br /&gt;기존 application.yml 대신 Config Server에서 중앙 관리되며, 각 서비스는 application-name.yml, application-dev.yml 등으로 설정을 로드한다.&lt;/p&gt;
&lt;h3 data-end=&quot;1089&quot; data-start=&quot;1075&quot; data-ke-size=&quot;size23&quot;&gt;  아키텍처 구성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WkmQz/btsPv7BnnmC/JTaK0AfiLvPH4PvGJ8MRpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WkmQz/btsPv7BnnmC/JTaK0AfiLvPH4PvGJ8MRpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WkmQz/btsPv7BnnmC/JTaK0AfiLvPH4PvGJ8MRpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWkmQz%2FbtsPv7BnnmC%2FJTaK0AfiLvPH4PvGJ8MRpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;335&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;335&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1220&quot; data-start=&quot;1193&quot; data-ke-size=&quot;size23&quot;&gt; ️ Config Server 설정 예시 (.yml)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753249428585&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/my-org/config-repo
          clone-on-start: true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1397&quot; data-start=&quot;1375&quot; data-ke-size=&quot;size23&quot;&gt;  클라이언트 서비스 설정 예시 (.yml)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753249443760&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  application:
    name: order-service
  cloud:
    config:
      uri: http://localhost:8888&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1582&quot; data-start=&quot;1513&quot; data-ke-size=&quot;size16&quot;&gt;해당 서비스는 order-service.yml 또는 application.yml을 중앙 저장소에서 자동으로 로드한다.&lt;/p&gt;
&lt;h2 data-end=&quot;1602&quot; data-start=&quot;1584&quot; data-ke-size=&quot;size26&quot;&gt;  Vault란 무엇인가?&lt;/h2&gt;
&lt;p data-end=&quot;1758&quot; data-start=&quot;1604&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Vault&lt;/b&gt;는 HashiCorp에서 제공하는 &lt;b&gt;비밀번호, API 키, DB 인증정보 등 민감 데이터를 안전하게 저장&amp;middot;관리하는 오픈소스 도구&lt;/b&gt;이다.&lt;br /&gt;일반 설정과는 달리 &lt;b&gt;시크릿(Secret)&lt;/b&gt; 관리는 별도로 해야 하며, Vault는 다음과 같은 장점을 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1842&quot; data-start=&quot;1760&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1775&quot; data-start=&quot;1760&quot;&gt;비밀 값 암호화 저장&lt;/li&gt;
&lt;li data-end=&quot;1796&quot; data-start=&quot;1776&quot;&gt;접근 권한 제어(Policy)&lt;/li&gt;
&lt;li data-end=&quot;1812&quot; data-start=&quot;1797&quot;&gt;토큰 기반 접근 인증&lt;/li&gt;
&lt;li data-end=&quot;1831&quot; data-start=&quot;1813&quot;&gt;DB 동적 자격 증명 발급&lt;/li&gt;
&lt;li data-end=&quot;1842&quot; data-start=&quot;1832&quot;&gt;감사 로그 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1906&quot; data-start=&quot;1844&quot; data-ke-size=&quot;size16&quot;&gt;Vault는 기본적으로 REST API를 통해 작동하며, Spring Boot와 연동 시 자동 설정이 가능하다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1947&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size26&quot;&gt;  Spring Cloud Config + Vault 통합 전략&lt;/h2&gt;
&lt;p data-end=&quot;2066&quot; data-start=&quot;1949&quot; data-ke-size=&quot;size16&quot;&gt;보통은 &lt;b&gt;Config Server로 일반 설정을, Vault로 민감한 시크릿을 분리 관리&lt;/b&gt;한다.&lt;br /&gt;Spring Cloud Vault를 통해 Vault에 저장된 값을 Spring 환경변수로 주입할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;2269&quot; data-start=&quot;2257&quot; data-ke-size=&quot;size23&quot;&gt;  예제 설정 (.yml)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753249486513&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  cloud:
    vault:
      uri: http://localhost:8200
      token: s.BjvxaD123abc456xyz
      kv:
        enabled: true
        backend: secret
        default-context: application&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2548&quot; data-start=&quot;2472&quot; data-ke-size=&quot;size16&quot;&gt;Vault 내의 /secret/application/db.password 값을 ${db.password} 형태로 사용할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;2568&quot; data-start=&quot;2550&quot; data-ke-size=&quot;size26&quot;&gt;  실무 적용 시 고려사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2799&quot; data-start=&quot;2570&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2654&quot; data-start=&quot;2570&quot;&gt;Config Server에 장애가 생기면 &lt;b&gt;전체 서비스 설정 로딩 실패&lt;/b&gt; 가능성이 있음&lt;br /&gt;&amp;rarr; 캐시 설정 또는 Fallback 전략 필요&lt;/li&gt;
&lt;li data-end=&quot;2698&quot; data-start=&quot;2655&quot;&gt;Vault는 &lt;b&gt;권한 제어 정책(Policy)을 꼼꼼히 설계&lt;/b&gt;해야 함&lt;/li&gt;
&lt;li data-end=&quot;2744&quot; data-start=&quot;2699&quot;&gt;Config Server와 Vault 간 통신도 암호화 및 인증 처리 필요&lt;/li&gt;
&lt;li data-end=&quot;2799&quot; data-start=&quot;2745&quot;&gt;운영 환경에서는 &lt;b&gt;Config Server와 Vault를 별도 서버로 격리&lt;/b&gt;하는 것이 안전&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2812&quot; data-start=&quot;2801&quot; data-ke-size=&quot;size26&quot;&gt;  장점 요약&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;3102&quot; data-start=&quot;2814&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;Spring Cloud Config&lt;/td&gt;
&lt;td&gt;Vault&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2922&quot; data-start=&quot;2890&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2898&quot; data-start=&quot;2890&quot;&gt;주요 목적&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2910&quot; data-start=&quot;2898&quot;&gt;일반 설정 중앙화&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2922&quot; data-start=&quot;2910&quot;&gt;민감 정보 보호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2970&quot; data-start=&quot;2923&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2933&quot; data-start=&quot;2923&quot;&gt;데이터 저장소&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2951&quot; data-start=&quot;2933&quot;&gt;Git, Local File&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2970&quot; data-start=&quot;2951&quot;&gt;Key-Value (암호화)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3019&quot; data-start=&quot;2971&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2979&quot; data-start=&quot;2971&quot;&gt;자동 갱신&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3000&quot; data-start=&quot;2979&quot;&gt;가능 (@RefreshScope)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3019&quot; data-start=&quot;3000&quot;&gt;Spring Vault 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3063&quot; data-start=&quot;3020&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3028&quot; data-start=&quot;3020&quot;&gt;인증 방식&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3043&quot; data-start=&quot;3028&quot;&gt;없음 또는 Git 인증&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3063&quot; data-start=&quot;3043&quot;&gt;Token, AppRole 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3102&quot; data-start=&quot;3064&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3076&quot; data-start=&quot;3064&quot;&gt;Spring 통합&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3085&quot; data-start=&quot;3076&quot;&gt;매우 뛰어남&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3102&quot; data-start=&quot;3085&quot;&gt;전용 Starter 존재&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;3111&quot; data-start=&quot;3104&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3281&quot; data-start=&quot;3113&quot; data-ke-size=&quot;size16&quot;&gt;MSA 환경에서 설정을 관리하지 않으면 장애는 필연적이다.&lt;br /&gt;&lt;b&gt;Spring Cloud Config&lt;/b&gt;는 설정의 일관성과 운영 편의성을 제공하고,&lt;br /&gt;&lt;b&gt;Vault&lt;/b&gt;는 민감 정보의 보안성을 보장한다.&lt;br /&gt;두 도구를 적절히 조합하면 &lt;b&gt;확장성과 보안성을 모두 갖춘 MSA 인프라 구성&lt;/b&gt;이 가능하다.&lt;/p&gt;
&lt;h2 data-end=&quot;3298&quot; data-start=&quot;3283&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3539&quot; data-start=&quot;3300&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3379&quot; data-start=&quot;3300&quot;&gt;&lt;a href=&quot;https://spring.io/projects/spring-cloud-config&quot; data-end=&quot;3377&quot; data-start=&quot;3302&quot;&gt;Spring Cloud Config 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3482&quot; data-start=&quot;3380&quot;&gt;&lt;a data-end=&quot;3480&quot; data-start=&quot;3382&quot;&gt;Spring Cloud Vault 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3539&quot; data-start=&quot;3483&quot;&gt;&lt;a data-end=&quot;3539&quot; data-start=&quot;3485&quot;&gt;HashiCorp Vault 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3657&quot; data-start=&quot;3565&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>MSA</category>
      <category>MSA설정전략</category>
      <category>SpringBoot설정</category>
      <category>springcloudconfig</category>
      <category>SpringCloud인프라</category>
      <category>vault</category>
      <category>마이크로서비스보안</category>
      <category>설정중앙화</category>
      <category>시크릿관리</category>
      <category>환경변수관리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1059</guid>
      <comments>https://monkeybusiness.tistory.com/1059#entry1059comment</comments>
      <pubDate>Wed, 23 Jul 2025 22:46:29 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] Circuit Breaker로 장애 격리 설계 (Hystrix, Resilience4j)</title>
      <link>https://monkeybusiness.tistory.com/1058</link>
      <description>&lt;p data-end=&quot;503&quot; data-start=&quot;265&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 각 서비스가 독립적으로 운영되지만, &lt;b&gt;서비스 간의 호출이 많아질수록 장애 전파의 위험성도 커진다.&lt;/b&gt;&lt;br /&gt;한 서비스의 장애가 전체 시스템 장애로 이어지는 상황을 막기 위해 등장한 개념이 바로 &lt;b&gt;서킷 브레이커(Circuit Breaker)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUAPL9/btsPun6VklJ/leS8J2qbHmpyblaeIPo6R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUAPL9/btsPun6VklJ/leS8J2qbHmpyblaeIPo6R0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUAPL9/btsPun6VklJ/leS8J2qbHmpyblaeIPo6R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUAPL9%2FbtsPun6VklJ%2FleS8J2qbHmpyblaeIPo6R0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;536&quot; data-start=&quot;505&quot; data-ke-size=&quot;size26&quot;&gt;✅ 서킷 브레이커(Circuit Breaker)란?&lt;/h2&gt;
&lt;p data-end=&quot;638&quot; data-start=&quot;538&quot; data-ke-size=&quot;size16&quot;&gt;서킷 브레이커는 전기 회로 차단기의 원리에서 따온 개념으로, &lt;b&gt;연결된 시스템이 일정 횟수 이상 실패하면 자동으로 호출을 중단하고, 우회하거나 예외를 빠르게 반환하는 패턴&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;683&quot; data-start=&quot;640&quot; data-ke-size=&quot;size16&quot;&gt;즉, 오류가 지속되면 회로를 끊어 더 이상의 자원 낭비나 장애 전파를 막는다.&lt;/p&gt;
&lt;h3 data-end=&quot;699&quot; data-start=&quot;685&quot; data-ke-size=&quot;size23&quot;&gt;  왜 필요한가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;785&quot; data-start=&quot;701&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;713&quot; data-start=&quot;701&quot;&gt;장애 전파 차단&lt;/li&gt;
&lt;li data-end=&quot;739&quot; data-start=&quot;714&quot;&gt;성능 저하 방지 (타임아웃 반복 방지)&lt;/li&gt;
&lt;li data-end=&quot;764&quot; data-start=&quot;740&quot;&gt;사용자 경험 보호 (빠른 실패 반환)&lt;/li&gt;
&lt;li data-end=&quot;785&quot; data-start=&quot;765&quot;&gt;시스템 자원의 불필요한 낭비 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;806&quot; data-start=&quot;787&quot; data-ke-size=&quot;size26&quot;&gt;  서킷 브레이커 동작 방식&lt;/h2&gt;
&lt;p data-end=&quot;835&quot; data-start=&quot;808&quot; data-ke-size=&quot;size16&quot;&gt;서킷 브레이커는 보통 다음 3가지 상태를 가진다.&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1034&quot; data-start=&quot;837&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;상태&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;901&quot; data-start=&quot;865&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;878&quot; data-start=&quot;865&quot;&gt;&lt;b&gt;Closed&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;901&quot; data-start=&quot;878&quot;&gt;정상 상태. 모든 요청이 통과한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;966&quot; data-start=&quot;902&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;913&quot; data-start=&quot;902&quot;&gt;&lt;b&gt;Open&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;966&quot; data-start=&quot;913&quot;&gt;일정 실패율 초과 시 차단 상태로 전환된다. 일정 시간 동안 요청이 바로 실패 처리된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1034&quot; data-start=&quot;967&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;983&quot; data-start=&quot;967&quot;&gt;&lt;b&gt;Half-Open&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;1034&quot; data-start=&quot;983&quot;&gt;일정 시간이 지나고 일부 요청만 허용한다. 요청이 성공하면 다시 Closed로 전환된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1072&quot; data-start=&quot;1036&quot; data-ke-size=&quot;size26&quot;&gt;  Hystrix: Netflix의 고전적인 서킷 브레이커&lt;/h2&gt;
&lt;p data-end=&quot;1186&quot; data-start=&quot;1074&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hystrix&lt;/b&gt;는 Netflix가 개발한 초기 MSA 서킷 브레이커 라이브러리이다.&lt;br /&gt;Spring Cloud Netflix를 통해 간단하게 사용할 수 있으며, 오랜 기간 표준처럼 사용되어 왔다.&lt;/p&gt;
&lt;h3 data-end=&quot;1205&quot; data-start=&quot;1188&quot; data-ke-size=&quot;size23&quot;&gt;  Hystrix 예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248253984&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@HystrixCommand(fallbackMethod = &quot;getDefaultUser&quot;)
public UserDto getUser(Long id) {
    return restTemplate.getForObject(&quot;http://user-service/api/users/&quot; + id, UserDto.class);
}

public UserDto getDefaultUser(Long id) {
    return new UserDto(&quot;Unknown&quot;, &quot;N/A&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1493&quot; data-start=&quot;1485&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1575&quot; data-start=&quot;1495&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1514&quot; data-start=&quot;1495&quot;&gt;간단한 어노테이션 기반 설정&lt;/li&gt;
&lt;li data-end=&quot;1539&quot; data-start=&quot;1515&quot;&gt;Spring Cloud에서 기본 통합&lt;/li&gt;
&lt;li data-end=&quot;1575&quot; data-start=&quot;1540&quot;&gt;Fallback 처리, 타임아웃, 스레드 격리 등 기능 다양&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1585&quot; data-start=&quot;1577&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1679&quot; data-start=&quot;1587&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1631&quot; data-start=&quot;1587&quot;&gt;현재는 &lt;b&gt;Netflix에서 개발 중단&lt;/b&gt;되었으며 유지보수 되지 않는다.&lt;/li&gt;
&lt;li data-end=&quot;1679&quot; data-start=&quot;1632&quot;&gt;Spring Cloud에서도 점점 &lt;b&gt;Resilience4j&lt;/b&gt;로 대체되고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1713&quot; data-start=&quot;1681&quot; data-ke-size=&quot;size26&quot;&gt;  Resilience4j: 현대적인 서킷 브레이커&lt;/h2&gt;
&lt;p data-end=&quot;1848&quot; data-start=&quot;1715&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Resilience4j&lt;/b&gt;는 Hystrix의 대체 라이브러리로, &lt;b&gt;Java 8 함수형 스타일&lt;/b&gt;, &lt;b&gt;모듈화&lt;/b&gt;, &lt;b&gt;경량화&lt;/b&gt;를 특징으로 한다.&lt;br /&gt;Spring Boot 2.x부터는 기본으로 Resilience4j 연동을 권장한다.&lt;/p&gt;
&lt;h3 data-end=&quot;1881&quot; data-start=&quot;1850&quot; data-ke-size=&quot;size23&quot;&gt; ️ 설정 방법 (application.yml)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248262744&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;resilience4j:
  circuitbreaker:
    instances:
      userService:
        registerHealthIndicator: true
        slidingWindowSize: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 10s&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2117&quot; data-start=&quot;2100&quot; data-ke-size=&quot;size23&quot;&gt;  Java 코드 예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248269936&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@CircuitBreaker(name = &quot;userService&quot;, fallbackMethod = &quot;fallbackUser&quot;)
public UserDto getUser(Long id) {
    return restTemplate.getForObject(&quot;http://user-service/api/users/&quot; + id, UserDto.class);
}

public UserDto fallbackUser(Long id, Throwable t) {
    return new UserDto(&quot;Fallback User&quot;, &quot;Offline&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2446&quot; data-start=&quot;2438&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2600&quot; data-start=&quot;2448&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2505&quot; data-start=&quot;2448&quot;&gt;모듈화 구조 (CircuitBreaker, RateLimiter, Retry, Bulkhead 등)&lt;/li&gt;
&lt;li data-end=&quot;2537&quot; data-start=&quot;2506&quot;&gt;Spring Boot Actuator와 통합 가능&lt;/li&gt;
&lt;li data-end=&quot;2568&quot; data-start=&quot;2538&quot;&gt;&lt;b&gt;비동기/반응형(WebFlux) 환경 지원&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2600&quot; data-start=&quot;2569&quot;&gt;Netflix Hystrix 대비 &lt;b&gt;가볍고 최신&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2610&quot; data-start=&quot;2602&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2644&quot; data-start=&quot;2612&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2644&quot; data-start=&quot;2612&quot;&gt;설정 항목이 많아 처음에는 진입장벽이 느껴질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2678&quot; data-start=&quot;2646&quot; data-ke-size=&quot;size26&quot;&gt;  Hystrix vs Resilience4j 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2992&quot; data-start=&quot;2680&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;Hystrix&lt;/td&gt;
&lt;td&gt;Resilience4j&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2774&quot; data-start=&quot;2747&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2753&quot; data-start=&quot;2747&quot;&gt;개발사&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2763&quot; data-start=&quot;2753&quot;&gt;Netflix&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2774&quot; data-start=&quot;2763&quot;&gt;독립 오픈소스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2807&quot; data-start=&quot;2775&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2783&quot; data-start=&quot;2775&quot;&gt;개발 상태&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2793&quot; data-start=&quot;2783&quot;&gt;유지보수 중단&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2807&quot; data-start=&quot;2793&quot;&gt;활발히 유지보수 중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2871&quot; data-start=&quot;2808&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2820&quot; data-start=&quot;2808&quot;&gt;Spring 연동&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2843&quot; data-start=&quot;2820&quot;&gt;Spring Cloud Netflix&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2871&quot; data-start=&quot;2843&quot;&gt;Spring Boot 2.x 이후 공식 채택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2916&quot; data-start=&quot;2872&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2881&quot; data-start=&quot;2872&quot;&gt;비동기 지원&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2889&quot; data-start=&quot;2881&quot;&gt;일부 지원&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2916&quot; data-start=&quot;2889&quot;&gt;완전 지원 (RxJava, Reactor)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2961&quot; data-start=&quot;2917&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2925&quot; data-start=&quot;2917&quot;&gt;기능 확장&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2931&quot; data-start=&quot;2925&quot;&gt;제한적&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2961&quot; data-start=&quot;2931&quot;&gt;모듈화 (Retry, RateLimiter 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2992&quot; data-start=&quot;2962&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2967&quot; data-start=&quot;2962&quot;&gt;성능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2979&quot; data-start=&quot;2967&quot;&gt;상대적으로 무거움&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2992&quot; data-start=&quot;2979&quot;&gt;경량 설계, 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;3015&quot; data-start=&quot;2994&quot; data-ke-size=&quot;size26&quot;&gt;  실무에서 어떻게 활용하는가?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3233&quot; data-start=&quot;3017&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3084&quot; data-start=&quot;3017&quot;&gt;&lt;b&gt;Spring Cloud Netflix 프로젝트&lt;/b&gt;라면 Hystrix를 기존 코드에 빠르게 적용할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;3155&quot; data-start=&quot;3085&quot;&gt;&lt;b&gt;신규 프로젝트&lt;/b&gt;나 Spring Boot 2.x 이상에서는 Resilience4j를 사용하는 것이 권장된다.&lt;/li&gt;
&lt;li data-end=&quot;3233&quot; data-start=&quot;3156&quot;&gt;장애 감지가 필요한 외부 서비스 호출, 결제 API 연동, 주문 시스템의 핵심 흐름 등에 &lt;b&gt;반드시 서킷 브레이커 적용이 필요하다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;3242&quot; data-start=&quot;3235&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3433&quot; data-start=&quot;3244&quot; data-ke-size=&quot;size16&quot;&gt;서킷 브레이커는 MSA 환경에서 &lt;b&gt;장애 전파를 막고 시스템 안정성을 보장하는 핵심 전략&lt;/b&gt;이다.&lt;br /&gt;Hystrix는 과거 표준이었지만, 이제는 유지보수가 중단되었고, Resilience4j가 그 자리를 대체하고 있다.&lt;br /&gt;단순한 라이브러리 선택을 넘어 &lt;b&gt;장애에 강한 시스템을 설계한다는 관점에서 반드시 고려해야 하는 기술 요소&lt;/b&gt;이다.&lt;/p&gt;
&lt;h2 data-end=&quot;3450&quot; data-start=&quot;3435&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3696&quot; data-start=&quot;3452&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3513&quot; data-start=&quot;3452&quot;&gt;&lt;a data-end=&quot;3511&quot; data-start=&quot;3454&quot;&gt;Resilience4j 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3633&quot; data-start=&quot;3514&quot;&gt;&lt;a data-end=&quot;3631&quot; data-start=&quot;3516&quot;&gt;Spring Cloud Circuit Breaker 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3696&quot; data-start=&quot;3634&quot;&gt;&lt;a href=&quot;https://github.com/Netflix/Hystrix&quot; data-end=&quot;3696&quot; data-start=&quot;3636&quot;&gt;Netflix Hystrix GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3825&quot; data-start=&quot;3722&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>CircuitBreaker패턴</category>
      <category>Fallback처리</category>
      <category>Hystrix</category>
      <category>MSA</category>
      <category>MSA안정성</category>
      <category>Resilience4j</category>
      <category>springcloud</category>
      <category>마이크로서비스</category>
      <category>서킷브레이커</category>
      <category>장애격리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1058</guid>
      <comments>https://monkeybusiness.tistory.com/1058#entry1058comment</comments>
      <pubDate>Wed, 23 Jul 2025 21:49:03 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] Eureka와 Consul로 서비스 디스커버리 구현하기</title>
      <link>https://monkeybusiness.tistory.com/1057</link>
      <description>&lt;p data-end=&quot;423&quot; data-start=&quot;224&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)는 각 서비스가 독립적으로 운영된다.&lt;br /&gt;하지만 &lt;b&gt;클라이언트 또는 다른 서비스가 해당 서비스를 어떻게 찾을 수 있을까?&lt;/b&gt;&lt;br /&gt;고정된 IP나 URL을 쓴다면 MSA의 장점인 &lt;b&gt;확장성과 유연한 배포&lt;/b&gt;를 살릴 수 없다.&lt;br /&gt;이 문제를 해결하는 핵심 개념이 바로 &lt;b&gt;서비스 디스커버리(Service Discovery)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XkQLE/btsPwb4Hjo7/EsJVWgSCAbtLssSVSKRpxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XkQLE/btsPwb4Hjo7/EsJVWgSCAbtLssSVSKRpxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XkQLE/btsPwb4Hjo7/EsJVWgSCAbtLssSVSKRpxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXkQLE%2FbtsPwb4Hjo7%2FEsJVWgSCAbtLssSVSKRpxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;441&quot; data-start=&quot;425&quot; data-ke-size=&quot;size26&quot;&gt;✅ 서비스 디스커버리란?&lt;/h2&gt;
&lt;p data-end=&quot;577&quot; data-start=&quot;443&quot; data-ke-size=&quot;size16&quot;&gt;서비스 디스커버리는 마이크로서비스 환경에서 &lt;b&gt;서비스들의 위치(IP, 포트)를 동적으로 탐색하는 메커니즘&lt;/b&gt;이다.&lt;br /&gt;애플리케이션 인스턴스가 실행될 때 서비스 디스커버리에 등록되고, 다른 서비스가 호출할 때 이를 탐색해 위치 정보를 얻는다.&lt;/p&gt;
&lt;p data-end=&quot;698&quot; data-start=&quot;579&quot; data-ke-size=&quot;size16&quot;&gt;즉, IP를 하드코딩하지 않아도 &lt;b&gt;서비스 이름만으로 통신&lt;/b&gt;이 가능해진다.&lt;br /&gt;이는 특히 &lt;b&gt;자동 확장(Auto Scaling)&lt;/b&gt;이나 &lt;b&gt;컨테이너 기반 배포(Docker, Kubernetes)&lt;/b&gt;에서 유용하다.&lt;/p&gt;
&lt;h3 data-end=&quot;717&quot; data-start=&quot;700&quot; data-ke-size=&quot;size23&quot;&gt;  등록과 검색의 흐름&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;865&quot; data-start=&quot;719&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;780&quot; data-start=&quot;719&quot;&gt;각 마이크로서비스가 서비스 디스커버리 서버에 &lt;b&gt;자신의 정보(IP, 포트, 상태 등)를 등록&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;833&quot; data-start=&quot;781&quot;&gt;호출하려는 서비스는 디스커버리 서버에 요청하여 &lt;b&gt;해당 서비스의 위치를 조회&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;865&quot; data-start=&quot;834&quot;&gt;필요 시 로드밸런싱이나 헬스 체크도 함께 수행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;890&quot; data-start=&quot;867&quot; data-ke-size=&quot;size26&quot;&gt;  대표적인 서비스 디스커버리 도구&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1069&quot; data-start=&quot;892&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;도구&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;td&gt;특징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;998&quot; data-start=&quot;932&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;945&quot; data-start=&quot;932&quot;&gt;&lt;b&gt;Eureka&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;974&quot; data-start=&quot;945&quot;&gt;Netflix에서 개발한 서비스 디스커버리 서버&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;998&quot; data-start=&quot;974&quot;&gt;Spring Cloud와 완벽한 호환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1069&quot; data-start=&quot;999&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1012&quot; data-start=&quot;999&quot;&gt;&lt;b&gt;Consul&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1042&quot; data-start=&quot;1012&quot;&gt;HashiCorp에서 만든 서비스 네트워크 플랫폼&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1069&quot; data-start=&quot;1042&quot;&gt;Key-Value 저장소, 헬스 체크 내장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;두 솔루션 모두 &lt;/span&gt;&lt;b&gt;서비스 등록/탐색/상태 확인&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 기능을 제공하며, Spring Cloud에서 쉽게 통합해 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1171&quot; data-start=&quot;1143&quot; data-ke-size=&quot;size26&quot;&gt;  Eureka로 서비스 디스커버리 구현하기&lt;/h2&gt;
&lt;p data-end=&quot;1284&quot; data-start=&quot;1173&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Eureka Server&lt;/b&gt;는 Spring Boot 애플리케이션으로 구동된다.&lt;br /&gt;모든 서비스들은 @EnableEurekaClient를 통해 자신을 등록하며, 디스커버리 클라이언트로 활용한다.&lt;/p&gt;
&lt;h3 data-end=&quot;1309&quot; data-start=&quot;1286&quot; data-ke-size=&quot;size23&quot;&gt;1. Eureka Server 설정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248030633&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApplication {
    public static void main(String[] args) {
        SpringApplication.run(DiscoveryApplication.class, args);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1549&quot; data-start=&quot;1521&quot; data-ke-size=&quot;size23&quot;&gt;2. application.yml 설정 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248039184&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;eureka:
  client:
    register-with-eureka: false
    fetch-registry: false&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1665&quot; data-start=&quot;1640&quot; data-ke-size=&quot;size23&quot;&gt;3. 마이크로서비스에서 클라이언트 설정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248047856&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FeignClient(name = &quot;user-service&quot;)
public interface UserClient {
    @GetMapping(&quot;/api/users/{id}&quot;)
    UserDto getUser(@PathVariable Long id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1876&quot; data-start=&quot;1827&quot; data-ke-size=&quot;size16&quot;&gt;서비스 이름 user-service만으로 &lt;b&gt;IP와 포트 없이도 호출이 가능&lt;/b&gt;하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1906&quot; data-start=&quot;1878&quot; data-ke-size=&quot;size26&quot;&gt;  Consul로 서비스 디스커버리 구현하기&lt;/h2&gt;
&lt;p data-end=&quot;2003&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Consul&lt;/b&gt;은 Key-Value 저장소와 헬스체크를 기본 제공하며, &lt;b&gt;멀티 데이터센터 지원&lt;/b&gt;, &lt;b&gt;DNS 통합&lt;/b&gt;, &lt;b&gt;서비스 상태 관리&lt;/b&gt; 등에 강점이 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;2024&quot; data-start=&quot;2005&quot; data-ke-size=&quot;size23&quot;&gt;1. Consul 서버 실행&lt;/h3&gt;
&lt;p data-end=&quot;2055&quot; data-start=&quot;2026&quot; data-ke-size=&quot;size16&quot;&gt;로컬 테스트 시 Docker로 간단히 실행 가능하다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248057112&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name=dev-consul -p 8500:8500 consul&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2147&quot; data-start=&quot;2122&quot; data-ke-size=&quot;size23&quot;&gt;2. application.yml 설정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248069104&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  cloud:
    consul:
      discovery:
        service-name: order-service
      host: localhost
      port: 8500&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2316&quot; data-start=&quot;2283&quot; data-ke-size=&quot;size23&quot;&gt;3. 서비스 간 호출 (RestTemplate 예시)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753248080776&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Autowired
private RestTemplate restTemplate;

public String getUserName() {
    return restTemplate.getForObject(&quot;http://user-service/api/users/1&quot;, String.class);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2533&quot; data-start=&quot;2497&quot; data-ke-size=&quot;size16&quot;&gt;Consul에 등록된 서비스명을 통해 IP 없이 호출할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;2560&quot; data-start=&quot;2535&quot; data-ke-size=&quot;size26&quot;&gt;  Eureka vs Consul 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2853&quot; data-start=&quot;2562&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;Eureka&lt;/td&gt;
&lt;td&gt;Consul&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2643&quot; data-start=&quot;2614&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2620&quot; data-start=&quot;2614&quot;&gt;개발사&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2630&quot; data-start=&quot;2620&quot;&gt;Netflix&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2643&quot; data-start=&quot;2630&quot;&gt;HashiCorp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2685&quot; data-start=&quot;2644&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2662&quot; data-start=&quot;2644&quot;&gt;Spring Cloud 연동&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2673&quot; data-start=&quot;2662&quot;&gt;최적화되어 있음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2685&quot; data-start=&quot;2673&quot;&gt;일부 설정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2716&quot; data-start=&quot;2686&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2696&quot; data-start=&quot;2686&quot;&gt;헬스체크 기능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2707&quot; data-start=&quot;2696&quot;&gt;클라이언트 기반&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2716&quot; data-start=&quot;2707&quot;&gt;자체 내장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2750&quot; data-start=&quot;2717&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2733&quot; data-start=&quot;2717&quot;&gt;Key-Value 저장소&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2743&quot; data-start=&quot;2733&quot;&gt;제공하지 않음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2750&quot; data-start=&quot;2743&quot;&gt;제공함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2778&quot; data-start=&quot;2751&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2759&quot; data-start=&quot;2751&quot;&gt;UI 제공&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2764&quot; data-start=&quot;2759&quot;&gt;있음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2778&quot; data-start=&quot;2764&quot;&gt;있음 (더 직관적)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2806&quot; data-start=&quot;2779&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2789&quot; data-start=&quot;2779&quot;&gt;클러스터 구성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2794&quot; data-start=&quot;2789&quot;&gt;단순&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2806&quot; data-start=&quot;2794&quot;&gt;복잡하지만 강력&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2853&quot; data-start=&quot;2807&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2823&quot; data-start=&quot;2807&quot;&gt;Kubernetes 통합&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2828&quot; data-start=&quot;2823&quot;&gt;약함&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2853&quot; data-start=&quot;2828&quot;&gt;강함 (Service Mesh에 강함)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2875&quot; data-start=&quot;2855&quot; data-ke-size=&quot;size26&quot;&gt; ️ 언제 어떤 도구를 쓸까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3041&quot; data-start=&quot;2877&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2919&quot; data-start=&quot;2877&quot;&gt;&lt;b&gt;Spring Cloud 중심 + 빠른 적용&lt;/b&gt; &amp;rarr; Eureka&lt;/li&gt;
&lt;li data-end=&quot;2968&quot; data-start=&quot;2920&quot;&gt;&lt;b&gt;Kubernetes 기반 or 인프라 통합 강화 필요&lt;/b&gt; &amp;rarr; Consul&lt;/li&gt;
&lt;li data-end=&quot;3008&quot; data-start=&quot;2969&quot;&gt;&lt;b&gt;서비스 헬스체크와 상태 동기화가 중요&lt;/b&gt; &amp;rarr; Consul&lt;/li&gt;
&lt;li data-end=&quot;3041&quot; data-start=&quot;3009&quot;&gt;&lt;b&gt;간단하고 직관적인 구성 원함&lt;/b&gt; &amp;rarr; Eureka&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3173&quot; data-start=&quot;3043&quot; data-ke-size=&quot;size16&quot;&gt;최근에는 Kubernetes의 &lt;b&gt;내장 서비스 디스커버리(DNS 기반)&lt;/b&gt;를 함께 사용하는 경우도 많지만,&lt;br /&gt;&lt;b&gt;서비스 레지스트리와 헬스 체크를 통합적으로 관리&lt;/b&gt;하려면 여전히 Eureka 또는 Consul이 좋은 선택이다.&lt;/p&gt;
&lt;h2 data-end=&quot;3182&quot; data-start=&quot;3175&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3374&quot; data-start=&quot;3184&quot; data-ke-size=&quot;size16&quot;&gt;MSA 환경에서 서비스 디스커버리는 &lt;b&gt;기본이자 필수 인프라 구성요소&lt;/b&gt;이다.&lt;br /&gt;Spring Cloud 기반이라면 Eureka로 빠르게 시작할 수 있고, 클라우드 네이티브 또는 인프라 통합이 중요하다면 Consul이 적합하다.&lt;br /&gt;서비스가 많아질수록 디스커버리 시스템의 역할은 커지므로, 초기 설계부터 신중하게 선택하는 것이 좋다.&lt;/p&gt;
&lt;h2 data-end=&quot;3391&quot; data-start=&quot;3376&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3684&quot; data-start=&quot;3393&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3529&quot; data-start=&quot;3393&quot;&gt;&lt;a data-end=&quot;3527&quot; data-start=&quot;3395&quot;&gt;Spring Cloud Netflix Eureka 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3583&quot; data-start=&quot;3530&quot;&gt;&lt;a data-end=&quot;3581&quot; data-start=&quot;3532&quot;&gt;HashiCorp Consul 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3684&quot; data-start=&quot;3584&quot;&gt;&lt;a data-end=&quot;3684&quot; data-start=&quot;3586&quot;&gt;Spring Cloud Consul 가이드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3816&quot; data-start=&quot;3710&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>consul</category>
      <category>Consul헬스체크</category>
      <category>eureka</category>
      <category>MSA</category>
      <category>MSA인프라</category>
      <category>servicediscovery</category>
      <category>springcloud</category>
      <category>마이크로서비스아키텍처</category>
      <category>서비스디스커버리</category>
      <category>서비스레지스트리</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1057</guid>
      <comments>https://monkeybusiness.tistory.com/1057#entry1057comment</comments>
      <pubDate>Wed, 23 Jul 2025 20:50:43 +0900</pubDate>
    </item>
    <item>
      <title>[MSA] 서비스 통신 방법 비교: Feign vs RESTTemplate vs WebClient</title>
      <link>https://monkeybusiness.tistory.com/1056</link>
      <description>&lt;p data-end=&quot;535&quot; data-start=&quot;243&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스 아키텍처(MSA)에서는 하나의 기능이 하나의 서비스로 나뉘기 때문에, 서비스 간 통신이 필수이다.&lt;br /&gt;인증 서비스가 사용자 정보를 가져오고, 주문 서비스가 상품 정보를 확인하는 등 &lt;b&gt;REST 기반의 서비스 간 호출은 매우 빈번&lt;/b&gt;하게 발생한다.&lt;br /&gt;이때 어떤 방식으로 다른 서비스를 호출할 것인가가 중요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nYSgD/btsPv0I4WDt/pqKtPcm8lwhRPvF517kXm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nYSgD/btsPv0I4WDt/pqKtPcm8lwhRPvF517kXm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nYSgD/btsPv0I4WDt/pqKtPcm8lwhRPvF517kXm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnYSgD%2FbtsPv0I4WDt%2FpqKtPcm8lwhRPvF517kXm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;654&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;564&quot; data-start=&quot;537&quot; data-ke-size=&quot;size26&quot;&gt;✅ MSA에서 서비스 간 통신이 필요한 이유&lt;/h2&gt;
&lt;p data-end=&quot;683&quot; data-start=&quot;566&quot; data-ke-size=&quot;size16&quot;&gt;MSA는 단일 시스템을 &lt;b&gt;기능별로 쪼갠 구조&lt;/b&gt;이다.&lt;br /&gt;따라서 사용자의 요청 하나를 처리하기 위해 &lt;b&gt;여러 서비스가 함께 동작&lt;/b&gt;해야 한다.&lt;br /&gt;예를 들어 사용자가 주문을 하면 다음과 같은 흐름이 전개된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;800&quot; data-start=&quot;685&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;717&quot; data-start=&quot;685&quot;&gt;주문 서비스 &amp;rarr; 사용자 서비스에서 유저 정보 조회&lt;/li&gt;
&lt;li data-end=&quot;746&quot; data-start=&quot;718&quot;&gt;주문 서비스 &amp;rarr; 상품 서비스에서 재고 확인&lt;/li&gt;
&lt;li data-end=&quot;770&quot; data-start=&quot;747&quot;&gt;주문 서비스 &amp;rarr; 결제 서비스 호출&lt;/li&gt;
&lt;li data-end=&quot;800&quot; data-start=&quot;771&quot;&gt;주문 완료 후 이벤트 발행 &amp;rarr; 배송 서비스 준비&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;873&quot; data-start=&quot;802&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 서비스 간 동기 호출이 필수적인 구조에서 &lt;b&gt;API 호출을 어떻게 구성하느냐가 곧 생산성과 유지보수성에 영향을 준다.&lt;/b&gt;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;893&quot; data-start=&quot;875&quot; data-ke-size=&quot;size26&quot;&gt;  RESTTemplate&lt;/h2&gt;
&lt;p data-end=&quot;988&quot; data-start=&quot;895&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RESTTemplate&lt;/b&gt;은 Spring 3부터 도입된 가장 기본적인 REST 클라이언트이다.&lt;br /&gt;지금도 많은 레거시 Spring 프로젝트에서 널리 사용되고 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;999&quot; data-start=&quot;990&quot; data-ke-size=&quot;size23&quot;&gt;  특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1080&quot; data-start=&quot;1001&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1036&quot; data-start=&quot;1001&quot;&gt;Http 요청을 전송하기 위한 다양한 메서드를 제공한다.&lt;/li&gt;
&lt;li data-end=&quot;1054&quot; data-start=&quot;1037&quot;&gt;동기 방식으로 작동한다.&lt;/li&gt;
&lt;li data-end=&quot;1080&quot; data-start=&quot;1055&quot;&gt;커스터마이징이 어렵고, 반복 코드가 많다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753247385857&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RestTemplate restTemplate = new RestTemplate();
ResponseEntity&amp;lt;UserDto&amp;gt; response =
    restTemplate.getForEntity(&quot;http://user-service/api/users/1&quot;, UserDto.class);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1267&quot; data-start=&quot;1259&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1332&quot; data-start=&quot;1269&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1292&quot; data-start=&quot;1269&quot;&gt;배우기 쉽고 레거시 호환성이 높다.&lt;/li&gt;
&lt;li data-end=&quot;1332&quot; data-start=&quot;1293&quot;&gt;다양한 HTTP Method 지원 (GET, POST, PUT 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1342&quot; data-start=&quot;1334&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1432&quot; data-start=&quot;1344&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1372&quot; data-start=&quot;1344&quot;&gt;반복 코드가 많고, 코드 가독성이 떨어진다.&lt;/li&gt;
&lt;li data-end=&quot;1390&quot; data-start=&quot;1373&quot;&gt;비동기 지원이 불편하다.&lt;/li&gt;
&lt;li data-end=&quot;1432&quot; data-start=&quot;1391&quot;&gt;Spring 5 이후로는 **비권장(deprecated 예정)**이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1449&quot; data-start=&quot;1434&quot; data-ke-size=&quot;size26&quot;&gt;  WebClient&lt;/h2&gt;
&lt;p data-end=&quot;1567&quot; data-start=&quot;1451&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WebClient&lt;/b&gt;는 Spring WebFlux에서 등장한 &lt;b&gt;비동기 논블로킹 HTTP 클라이언트&lt;/b&gt;이다.&lt;br /&gt;RESTTemplate의 대체자로 권장되며, WebFlux 기반이 아니더라도 사용 가능하다.&lt;/p&gt;
&lt;h3 data-end=&quot;1578&quot; data-start=&quot;1569&quot; data-ke-size=&quot;size23&quot;&gt;  특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1662&quot; data-start=&quot;1580&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1608&quot; data-start=&quot;1580&quot;&gt;Mono/Flux 기반의 반응형 API 제공&lt;/li&gt;
&lt;li data-end=&quot;1630&quot; data-start=&quot;1609&quot;&gt;비동기 처리로 성능 최적화 가능&lt;/li&gt;
&lt;li data-end=&quot;1662&quot; data-start=&quot;1631&quot;&gt;필터, 리트라이, 타임아웃 설정 등 확장성이 뛰어나다&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753247458304&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WebClient webClient = WebClient.create(&quot;http://user-service&quot;);

Mono&amp;lt;UserDto&amp;gt; mono = webClient.get()
    .uri(&quot;/api/users/1&quot;)
    .retrieve()
    .bodyToMono(UserDto.class);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1859&quot; data-start=&quot;1851&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1930&quot; data-start=&quot;1861&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1887&quot; data-start=&quot;1861&quot;&gt;비동기 처리로 &lt;b&gt;IO 병목이 적다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1909&quot; data-start=&quot;1888&quot;&gt;가볍고 유연한 설정이 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;1930&quot; data-start=&quot;1910&quot;&gt;Spring 공식 권장 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1940&quot; data-start=&quot;1932&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1995&quot; data-start=&quot;1942&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1969&quot; data-start=&quot;1942&quot;&gt;Mono/Flux에 대한 이해가 필요하다.&lt;/li&gt;
&lt;li data-end=&quot;1995&quot; data-start=&quot;1970&quot;&gt;단순 요청이라면 오히려 복잡해질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2015&quot; data-start=&quot;1997&quot; data-ke-size=&quot;size26&quot;&gt;  Feign Client&lt;/h2&gt;
&lt;p data-end=&quot;2109&quot; data-start=&quot;2017&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Feign&lt;/b&gt;은 Netflix OSS에서 제공하던 선언형 REST 클라이언트이다.&lt;br /&gt;인터페이스 기반으로 HTTP 요청을 선언만 하면 자동으로 구현체가 생성된다.&lt;/p&gt;
&lt;h3 data-end=&quot;2120&quot; data-start=&quot;2111&quot; data-ke-size=&quot;size23&quot;&gt;  특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2250&quot; data-start=&quot;2122&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2161&quot; data-start=&quot;2122&quot;&gt;@FeignClient 어노테이션 하나로 REST 호출 선언&lt;/li&gt;
&lt;li data-end=&quot;2214&quot; data-start=&quot;2162&quot;&gt;Spring Cloud와 통합되어 &lt;b&gt;서비스 디스커버리(Eureka)와 연동&lt;/b&gt;도 가능&lt;/li&gt;
&lt;li data-end=&quot;2250&quot; data-start=&quot;2215&quot;&gt;로드밸런싱, 장애 감지, 리트라이 등의 기능과 쉽게 통합된다&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753247542272&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FeignClient(name = &quot;user-service&quot;)
public interface UserClient {
    @GetMapping(&quot;/api/users/{id}&quot;)
    UserDto getUser(@PathVariable(&quot;id&quot;) Long id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2426&quot; data-start=&quot;2418&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2543&quot; data-start=&quot;2428&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2450&quot; data-start=&quot;2428&quot;&gt;코드 간결, 유지보수가 용이하다.&lt;/li&gt;
&lt;li data-end=&quot;2496&quot; data-start=&quot;2451&quot;&gt;Eureka/Consul과 함께 쓰면 &lt;b&gt;동적 서비스 호출&lt;/b&gt;이 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;2543&quot; data-start=&quot;2497&quot;&gt;요청 실패 처리(Circuit Breaker, Retry 등) 연동이 편리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2553&quot; data-start=&quot;2545&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2613&quot; data-start=&quot;2555&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2573&quot; data-start=&quot;2555&quot;&gt;디버깅이 어려울 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;2593&quot; data-start=&quot;2574&quot;&gt;복잡한 요청 설정은 어렵다.&lt;/li&gt;
&lt;li data-end=&quot;2613&quot; data-start=&quot;2594&quot;&gt;성능 오버헤드가 있을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2634&quot; data-start=&quot;2615&quot; data-ke-size=&quot;size26&quot;&gt;  세 가지 방식 비교 요약&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2958&quot; data-start=&quot;2636&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;RESTTemplate&lt;/td&gt;
&lt;td&gt;WebClient&lt;/td&gt;
&lt;td&gt;Feign&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2748&quot; data-start=&quot;2723&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2731&quot; data-start=&quot;2723&quot;&gt;호출 방식&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2736&quot; data-start=&quot;2731&quot;&gt;동기&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2742&quot; data-start=&quot;2736&quot;&gt;비동기&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2748&quot; data-start=&quot;2742&quot;&gt;동기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2779&quot; data-start=&quot;2749&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2755&quot; data-start=&quot;2749&quot;&gt;스타일&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2761&quot; data-start=&quot;2755&quot;&gt;명령형&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2772&quot; data-start=&quot;2761&quot;&gt;함수형, 반응형&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2779&quot; data-start=&quot;2772&quot;&gt;선언형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2808&quot; data-start=&quot;2780&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2789&quot; data-start=&quot;2780&quot;&gt;코드 간결성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2794&quot; data-start=&quot;2789&quot;&gt;낮음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2799&quot; data-start=&quot;2794&quot;&gt;중간&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2808&quot; data-start=&quot;2799&quot;&gt;매우 높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2834&quot; data-start=&quot;2809&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2815&quot; data-start=&quot;2809&quot;&gt;확장성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2820&quot; data-start=&quot;2815&quot;&gt;낮음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2828&quot; data-start=&quot;2820&quot;&gt;매우 높음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2834&quot; data-start=&quot;2828&quot;&gt;중간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2862&quot; data-start=&quot;2835&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2843&quot; data-start=&quot;2835&quot;&gt;학습 곡선&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2848&quot; data-start=&quot;2843&quot;&gt;낮음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2856&quot; data-start=&quot;2848&quot;&gt;중간~높음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2862&quot; data-start=&quot;2856&quot;&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2914&quot; data-start=&quot;2863&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2878&quot; data-start=&quot;2863&quot;&gt;Spring 권장 여부&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2890&quot; data-start=&quot;2878&quot;&gt;X (권장 안함)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2894&quot; data-start=&quot;2890&quot;&gt;O&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2914&quot; data-start=&quot;2894&quot;&gt;O (Spring Cloud)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2958&quot; data-start=&quot;2915&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2923&quot; data-start=&quot;2915&quot;&gt;특징 요약&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2933&quot; data-start=&quot;2923&quot;&gt;전통적인 방식&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2943&quot; data-start=&quot;2933&quot;&gt;비동기 고성능&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2958&quot; data-start=&quot;2943&quot;&gt;서비스 간 통신 특화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2986&quot; data-start=&quot;2960&quot; data-ke-size=&quot;size26&quot;&gt;  어떤 상황에서 어떤 방식을 선택할까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3125&quot; data-start=&quot;2988&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3032&quot; data-start=&quot;2988&quot;&gt;&lt;b&gt;간단한 내부 호출 / 레거시 시스템&lt;/b&gt; &amp;rarr; RESTTemplate&lt;/li&gt;
&lt;li data-end=&quot;3076&quot; data-start=&quot;3033&quot;&gt;&lt;b&gt;고성능 비동기 요청 / IO 병목 해결&lt;/b&gt; &amp;rarr; WebClient&lt;/li&gt;
&lt;li data-end=&quot;3125&quot; data-start=&quot;3077&quot;&gt;&lt;b&gt;MSA 구조에서 서비스 간 통신 중심 / 선언형 유지보수성&lt;/b&gt; &amp;rarr; Feign&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3259&quot; data-start=&quot;3127&quot; data-ke-size=&quot;size16&quot;&gt;대부분의 &lt;b&gt;Spring Cloud 기반 MSA&lt;/b&gt;에서는 Feign + WebClient를 조합해서 사용한다.&lt;br /&gt;Feign으로 일반적인 서비스 간 통신을 처리하고, 고성능이 필요한 부분은 WebClient로 최적화하는 방식이다.&lt;/p&gt;
&lt;h2 data-end=&quot;3268&quot; data-start=&quot;3261&quot; data-ke-size=&quot;size26&quot;&gt;✅ 결론&lt;/h2&gt;
&lt;p data-end=&quot;3508&quot; data-start=&quot;3270&quot; data-ke-size=&quot;size16&quot;&gt;MSA에서 서비스 간 통신은 &lt;b&gt;단순한 HTTP 요청이 아니라 아키텍처의 핵심 흐름&lt;/b&gt;이다.&lt;br /&gt;RESTTemplate은 이제는 레거시 방식으로 전환이 권장되며, WebClient는 비동기 고성능 처리에 적합하다.&lt;br /&gt;Feign은 선언형 스타일로 가장 간편하게 서비스 간 통신을 구현할 수 있어 실무에서 널리 사용된다.&lt;br /&gt;성능, 코드 복잡도, 팀 숙련도 등을 고려해 &lt;b&gt;프로젝트에 가장 적합한 통신 방식&lt;/b&gt;을 선택해야 한다.&lt;/p&gt;
&lt;h2 data-end=&quot;3525&quot; data-start=&quot;3510&quot; data-ke-size=&quot;size26&quot;&gt;  참고한 공식 문서&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3886&quot; data-start=&quot;3527&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3657&quot; data-start=&quot;3527&quot;&gt;&lt;a data-end=&quot;3655&quot; data-start=&quot;3529&quot;&gt;Spring WebClient 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3741&quot; data-start=&quot;3658&quot;&gt;&lt;a data-end=&quot;3739&quot; data-start=&quot;3660&quot;&gt;Spring Cloud OpenFeign 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;3886&quot; data-start=&quot;3742&quot;&gt;&lt;a data-end=&quot;3886&quot; data-start=&quot;3744&quot;&gt;Spring RESTTemplate 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4011&quot; data-start=&quot;3912&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MSA</category>
      <category>Feign</category>
      <category>MSA</category>
      <category>MSA아키텍처</category>
      <category>RestTemplate</category>
      <category>springcloud</category>
      <category>SpringWebflux</category>
      <category>WebClient</category>
      <category>마이크로서비스</category>
      <category>비동기통신</category>
      <category>서비스간통신</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1056</guid>
      <comments>https://monkeybusiness.tistory.com/1056#entry1056comment</comments>
      <pubDate>Wed, 23 Jul 2025 19:55:31 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 실무에서 자주 쓰는 날짜/시간 함수 조합 예제 모음</title>
      <link>https://monkeybusiness.tistory.com/1055</link>
      <description>&lt;p data-end=&quot;418&quot; data-start=&quot;239&quot; data-ke-size=&quot;size16&quot;&gt;지금까지 다양한 MySQL 날짜 및 시간 함수를 배웠다면, 이제는 그것들을 &lt;b&gt;실제로 어떻게 조합해서 사용하는지&lt;/b&gt;가 가장 중요하다. 실무에서는 단일 함수보다 &lt;b&gt;여러 함수를 조합하여 조건 처리, 리포트 출력, 시간 계산&lt;/b&gt;을 효율적으로 수행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yLSlv/btsPuDugNZL/YvcSgezURXhk7Z0PpYDxQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yLSlv/btsPuDugNZL/YvcSgezURXhk7Z0PpYDxQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yLSlv/btsPuDugNZL/YvcSgezURXhk7Z0PpYDxQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyLSlv%2FbtsPuDugNZL%2FYvcSgezURXhk7Z0PpYDxQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;444&quot; data-start=&quot;420&quot; data-ke-size=&quot;size26&quot;&gt;1. 오늘부터 최근 7일간 데이터 조회&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242807060&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM orders
WHERE order_date BETWEEN CURDATE() - INTERVAL 6 DAY AND CURDATE();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;642&quot; data-start=&quot;546&quot; data-ke-size=&quot;size16&quot;&gt;CURDATE는 오늘 날짜를 반환하고, - INTERVAL 6 DAY를 하면 &lt;b&gt;최근 7일&lt;/b&gt; 범위를 쉽게 만들 수 있다. 주간 리포트, 로그인 현황 등에 자주 사용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;670&quot; data-start=&quot;644&quot; data-ke-size=&quot;size26&quot;&gt;2. 특정 시간대에 생성된 데이터만 필터링&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242815356&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM log_table
WHERE TIME(created_at) BETWEEN '09:00:00' AND '18:00:00';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;847&quot; data-start=&quot;766&quot; data-ke-size=&quot;size16&quot;&gt;TIME()으로 DATETIME에서 시간만 뽑아 특정 시간대에 발생한 이벤트를 필터링할 수 있다. 근무시간, 심야 접속 분석 등에 활용된다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;863&quot; data-start=&quot;849&quot; data-ke-size=&quot;size26&quot;&gt;3. 월별 매출 집계&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242823372&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  YEAR(payment_date) AS 년도,
  MONTH(payment_date) AS 월,
  SUM(amount) AS 매출합계
FROM payments
GROUP BY 년도, 월
ORDER BY 년도 DESC, 월 DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1093&quot; data-start=&quot;1017&quot; data-ke-size=&quot;size16&quot;&gt;YEAR()와 MONTH()를 조합하면 월별 리포트를 쉽게 만들 수 있다. BI 도구나 통계 보고서에서 가장 많이 쓰이는 유형이다.&lt;/p&gt;
&lt;h2 data-end=&quot;1107&quot; data-start=&quot;1095&quot; data-ke-size=&quot;size26&quot;&gt;4. 분기별 집계&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242828222&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  YEAR(sale_date) AS 년도,
  QUARTER(sale_date) AS 분기,
  COUNT(*) AS 판매건수
FROM sales
GROUP BY 년도, 분기
ORDER BY 년도, 분기;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1320&quot; data-start=&quot;1244&quot; data-ke-size=&quot;size16&quot;&gt;QUARTER()는 회계 리포트나 투자 실적 분석에 자주 쓰이며 YEAR()와 함께 조합하면 연도별 분기 리포트를 완성할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1338&quot; data-start=&quot;1322&quot; data-ke-size=&quot;size26&quot;&gt;5. 다음달 말일 구하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242836252&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LAST_DAY(DATE_ADD(CURDATE(), INTERVAL 1 MONTH)) AS 다음달말일;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1506&quot; data-start=&quot;1417&quot; data-ke-size=&quot;size16&quot;&gt;DATE_ADD로 다음 달을 구하고, LAST_DAY로 해당 달의 마지막 날을 가져오는 조합이다. &lt;b&gt;청구일, 자동 갱신일 계산 등에서 필수&lt;/b&gt;로 쓰인다.&lt;/p&gt;
&lt;h2 data-end=&quot;1526&quot; data-start=&quot;1508&quot; data-ke-size=&quot;size26&quot;&gt;6. 요일별 접속 분포 분석&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242843189&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  DAYNAME(login_time) AS 요일,
  COUNT(*) AS 접속수
FROM user_logins
GROUP BY 요일
ORDER BY FIELD(요일, 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1799&quot; data-start=&quot;1721&quot; data-ke-size=&quot;size16&quot;&gt;DAYNAME()은 요일 이름을 반환하며, FIELD()를 활용하면 요일 순서대로 정렬이 가능하다. 서비스 이용 패턴 분석에 활용된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1820&quot; data-start=&quot;1801&quot; data-ke-size=&quot;size26&quot;&gt;7. 특정 날짜 포맷으로 출력&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242871116&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  DATE_FORMAT(order_date, '%Y년 %m월 %d일') AS 주문일자,
  TIME_FORMAT(order_date, '%H:%i:%s') AS 주문시간
FROM orders;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2046&quot; data-start=&quot;1950&quot; data-ke-size=&quot;size16&quot;&gt;화면에 &lt;b&gt;가독성 좋은 날짜와 시간&lt;/b&gt;을 표시하기 위해 DATE_FORMAT, TIME_FORMAT을 조합한다. 마이페이지, 인보이스, 알림 메시지 출력 등에 필수다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2075&quot; data-start=&quot;2048&quot; data-ke-size=&quot;size26&quot;&gt;8. 문자열 날짜를 비교 가능한 날짜로 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242876692&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM temp_import
WHERE STR_TO_DATE(order_date_txt, '%Y-%m-%d') BETWEEN CURDATE() - INTERVAL 30 DAY AND CURDATE();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2305&quot; data-start=&quot;2212&quot; data-ke-size=&quot;size16&quot;&gt;외부 파일(CSV, 엑셀 등)에서 들어온 문자열 날짜는 STR_TO_DATE()로 변환한 뒤 조건 비교해야 한다. &lt;b&gt;업로드 유효성 검증, 클렌징&lt;/b&gt;에 자주 쓰인다.&lt;/p&gt;
&lt;h2 data-end=&quot;2334&quot; data-start=&quot;2307&quot; data-ke-size=&quot;size26&quot;&gt;9. 현재 시각 기준 N초 이내 이벤트 조회&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242884741&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM realtime_events
WHERE UNIX_TIMESTAMP(event_time) &amp;gt;= UNIX_TIMESTAMP() - 60;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2504&quot; data-start=&quot;2437&quot; data-ke-size=&quot;size16&quot;&gt;UNIX_TIMESTAMP()를 양쪽에 사용하면 초 단위 비교가 가능해 &lt;b&gt;정밀한 실시간 이벤트 필터링&lt;/b&gt;이 가능하다.&lt;/p&gt;
&lt;h2 data-end=&quot;2534&quot; data-start=&quot;2506&quot; data-ke-size=&quot;size26&quot;&gt;10. 날짜/시간 계산 후 문자열로 포맷 출력&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242891404&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(DATE_ADD(NOW(), INTERVAL 3 DAY), '%Y-%m-%d %H:%i') AS 알림예정시각;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2697&quot; data-start=&quot;2629&quot; data-ke-size=&quot;size16&quot;&gt;지금부터 3일 뒤의 시간을 계산한 후 &lt;b&gt;가독성 좋은 형태로 포맷팅&lt;/b&gt;해준다. 알림 시스템, 일정 안내 메시지 등에 쓰인다.&lt;/p&gt;
&lt;h2 data-end=&quot;2709&quot; data-start=&quot;2699&quot; data-ke-size=&quot;size26&quot;&gt;실무 팁 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2978&quot; data-start=&quot;2711&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2750&quot; data-start=&quot;2711&quot;&gt;여러 날짜 함수는 &lt;b&gt;조합해서 쓰는 순간 그 진가를 발휘&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;2851&quot; data-start=&quot;2751&quot;&gt;DATE_ADD + LAST_DAY, YEAR + MONTH, STR_TO_DATE + 비교, TIME + 시간 필터링 등은 실무에서 가장 많이 쓰는 조합이다.&lt;/li&gt;
&lt;li data-end=&quot;2914&quot; data-start=&quot;2852&quot;&gt;집계 목적이면 GROUP BY와 함께 YEAR/MONTH/QUARTER/WEEK을 쓰는 것이 정석&lt;/li&gt;
&lt;li data-end=&quot;2978&quot; data-start=&quot;2915&quot;&gt;데이터 정제 목적이면 STR_TO_DATE, CAST, UNIX_TIMESTAMP를 필수로 활용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2988&quot; data-start=&quot;2980&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3058&quot; data-start=&quot;2990&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3157&quot; data-start=&quot;3076&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB실무쿼리</category>
      <category>MYSQL</category>
      <category>MySQL리포트</category>
      <category>Mysql조건문</category>
      <category>SQL날짜함수</category>
      <category>SQL패턴분석</category>
      <category>날짜비교</category>
      <category>데이터정제</category>
      <category>시간함수조합</category>
      <category>웹개발SQL</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1055</guid>
      <comments>https://monkeybusiness.tistory.com/1055#entry1055comment</comments>
      <pubDate>Wed, 23 Jul 2025 18:55:47 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] LAST_DAY, MAKEDATE, MAKETIME 등 특수 날짜 생성 함수</title>
      <link>https://monkeybusiness.tistory.com/1054</link>
      <description>&lt;p data-end=&quot;481&quot; data-start=&quot;274&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 단순히 날짜를 추출하거나 비교하는 것 외에도 &lt;b&gt;날짜를 생성하거나 구성하는 함수들&lt;/b&gt;이 존재한다. 이번 글에서는 실무에서 유용하게 쓰이는 &lt;b&gt;LAST_DAY&lt;/b&gt;, &lt;b&gt;MAKEDATE&lt;/b&gt;, &lt;b&gt;MAKETIME&lt;/b&gt;, &lt;b&gt;CURDATE() + 시간 조합&lt;/b&gt;, &lt;b&gt;EXTRACT()&lt;/b&gt; 등 날짜를 생성하거나 가공할 때 꼭 알아둬야 할 특수 날짜 함수들을 정리한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/do7eRc/btsPvh47EsC/yZoibDPSAlnQ3U4Xr48hh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/do7eRc/btsPvh47EsC/yZoibDPSAlnQ3U4Xr48hh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/do7eRc/btsPvh47EsC/yZoibDPSAlnQ3U4Xr48hh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdo7eRc%2FbtsPvh47EsC%2FyZoibDPSAlnQ3U4Xr48hh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;517&quot; data-start=&quot;483&quot; data-ke-size=&quot;size26&quot;&gt;LAST_DAY() 함수 &amp;ndash; 해당 달의 마지막 날 구하기&lt;/h2&gt;
&lt;p data-end=&quot;608&quot; data-start=&quot;519&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LAST_DAY()&lt;/b&gt; 함수는 특정 날짜가 속한 &lt;b&gt;월의 마지막 날짜를 반환&lt;/b&gt;하는 함수이다. 정산일, 급여 마감일, 말일 기준 리포트 등에서 자주 사용된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242529822&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LAST_DAY('2025-07-22');
-- 결과: 2025-07-31&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;695&quot; data-start=&quot;671&quot; data-ke-size=&quot;size23&quot;&gt;예제: 이번 달 말일 기준 일정 조회&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242536076&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM schedule
WHERE event_date = LAST_DAY(CURDATE());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;808&quot; data-start=&quot;772&quot; data-ke-size=&quot;size16&quot;&gt;오늘 날짜가 포함된 월의 마지막 날에 있는 일정만 가져올 수 있다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;843&quot; data-start=&quot;810&quot; data-ke-size=&quot;size26&quot;&gt;MAKEDATE() 함수 &amp;ndash; 연도와 일 수로 날짜 생성&lt;/h2&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;845&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MAKEDATE(year, day_of_year)&lt;/b&gt; 함수는 연도와 그 해의 &lt;b&gt;몇 번째 일&lt;/b&gt;을 기준으로 날짜를 생성한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242545572&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT MAKEDATE(2025, 1);
-- 결과: 2025-01-01

SELECT MAKEDATE(2025, 200);
-- 결과: 2025-07-19&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1040&quot; data-start=&quot;1020&quot; data-ke-size=&quot;size23&quot;&gt;예제: 통계용 더미 날짜 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242550916&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT MAKEDATE(2025, seq.day_number) AS 통계날짜
FROM generate_days seq
WHERE seq.day_number &amp;lt;= 365;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1189&quot; data-start=&quot;1152&quot; data-ke-size=&quot;size16&quot;&gt;연도별 데이터를 &lt;b&gt;1~365일 단위로 생성할 때 매우 유용&lt;/b&gt;하다.&lt;/p&gt;
&lt;h2 data-end=&quot;1217&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size26&quot;&gt;MAKETIME() 함수 &amp;ndash; 시간 값 생성&lt;/h2&gt;
&lt;p data-end=&quot;1293&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MAKETIME(hour, minute, second)&lt;/b&gt;는 시, 분, 초를 입력해서 &lt;b&gt;TIME 타입 값&lt;/b&gt;을 생성하는 함수이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242557364&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT MAKETIME(14, 30, 0);
-- 결과: 14:30:00&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1373&quot; data-start=&quot;1351&quot; data-ke-size=&quot;size23&quot;&gt;예제: 근무 시간대 고정 값 처리&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242564892&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT employee_id,
       MAKETIME(9, 0, 0) AS 출근시간,
       MAKETIME(18, 0, 0) AS 퇴근시간
FROM employees;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1523&quot; data-start=&quot;1491&quot; data-ke-size=&quot;size16&quot;&gt;고정된 시간대를 만들어서 업무 시간 계산에 활용할 수 있다.&lt;/p&gt;
&lt;h2 data-end=&quot;1544&quot; data-start=&quot;1525&quot; data-ke-size=&quot;size26&quot;&gt;DATE + TIME 조합하기&lt;/h2&gt;
&lt;p data-end=&quot;1632&quot; data-start=&quot;1546&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 날짜(DATE)와 시간(TIME)을 더해서 &lt;b&gt;DATETIME&lt;/b&gt; 형태로 만들 수 있다. 주로 CAST() 또는 단순 덧셈으로 처리한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242572060&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CURDATE() + INTERVAL 9 HOUR;
-- 결과: 오늘 오전 9시

SELECT CONCAT(CURDATE(), ' ', MAKETIME(14, 0, 0));
-- 결과: '2025-07-22 14:00:00'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1815&quot; data-start=&quot;1779&quot; data-ke-size=&quot;size16&quot;&gt;이런 방식은 &lt;b&gt;예약 시스템이나 시간별 스케줄 생성&lt;/b&gt;에 활용된다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1848&quot; data-start=&quot;1817&quot; data-ke-size=&quot;size26&quot;&gt;EXTRACT() 함수 &amp;ndash; 날짜에서 특정 필드 추출&lt;/h2&gt;
&lt;p data-end=&quot;1915&quot; data-start=&quot;1850&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EXTRACT()&lt;/b&gt;는 날짜에서 연도, 월, 일, 분기, 주차, 요일 등 다양한 구성 요소를 개별 추출할 수 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242578909&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT EXTRACT(DAY FROM '2025-07-22');
-- 결과: 22

SELECT EXTRACT(QUARTER FROM '2025-07-22');
-- 결과: 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2076&quot; data-start=&quot;2031&quot; data-ke-size=&quot;size16&quot;&gt;날짜를 조립하거나 조건문으로 분기할 때 &lt;b&gt;EXTRACT는 매우 강력한 도구&lt;/b&gt;다.&lt;/p&gt;
&lt;h2 data-end=&quot;2097&quot; data-start=&quot;2078&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 다음달 말일 계산&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242585724&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT LAST_DAY(DATE_ADD(CURDATE(), INTERVAL 1 MONTH)) AS 다음달_말일;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2216&quot; data-start=&quot;2177&quot; data-ke-size=&quot;size16&quot;&gt;매달 &lt;b&gt;자동 청구일 계산, 다음 달 일정 등록&lt;/b&gt; 등에 사용하기 좋다.&lt;/p&gt;
&lt;h2 data-end=&quot;2242&quot; data-start=&quot;2218&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 문자열 시간 생성 후 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242591740&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE(CONCAT('2025-07-22 ', MAKETIME(15, 45, 0)), '%Y-%m-%d %H:%i:%s');
-- 결과: 2025-07-22 15:45:00&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2421&quot; data-start=&quot;2368&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 MAKETIME으로 만든 시간을 날짜와 붙여서 &lt;b&gt;정밀한 시각 데이터 생성이 가능&lt;/b&gt;하다.&lt;/p&gt;
&lt;h2 data-end=&quot;2428&quot; data-start=&quot;2423&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2670&quot; data-start=&quot;2430&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2479&quot; data-start=&quot;2430&quot;&gt;LAST_DAY()는 해당 달의 마지막 날을 반환하며, 말일 기준 작업에 유용&lt;/li&gt;
&lt;li data-end=&quot;2522&quot; data-start=&quot;2480&quot;&gt;MAKEDATE()는 연도 + 몇 번째 날 조합으로 날짜를 만든다.&lt;/li&gt;
&lt;li data-end=&quot;2567&quot; data-start=&quot;2523&quot;&gt;MAKETIME()은 시, 분, 초를 기반으로 TIME 값을 생성한다.&lt;/li&gt;
&lt;li data-end=&quot;2623&quot; data-start=&quot;2568&quot;&gt;날짜와 시간은 CONCAT, CAST, + INTERVAL 등으로 조합할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;2670&quot; data-start=&quot;2624&quot;&gt;EXTRACT()는 날짜를 세부 단위로 쪼개 활용할 수 있는 필수 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2680&quot; data-start=&quot;2672&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3034&quot; data-start=&quot;2682&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_last-day&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_last-day&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_makedate&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_makedate&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_maketime&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_maketime&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_extract&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_extract&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3143&quot; data-start=&quot;3052&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB날짜처리</category>
      <category>lastday</category>
      <category>MAKEDATE</category>
      <category>MAKETIME</category>
      <category>MYSQL</category>
      <category>MySQL날짜생성</category>
      <category>MySQL예제모음</category>
      <category>SQL시간함수</category>
      <category>SQL일정계산</category>
      <category>특수날짜함수</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1054</guid>
      <comments>https://monkeybusiness.tistory.com/1054#entry1054comment</comments>
      <pubDate>Wed, 23 Jul 2025 17:50:35 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] WEEK, MONTH, QUARTER, YEARWEEK 등 기간 단위 함수 모음  ️</title>
      <link>https://monkeybusiness.tistory.com/1053</link>
      <description>&lt;p data-end=&quot;472&quot; data-start=&quot;261&quot; data-ke-size=&quot;size16&quot;&gt;웹 서비스나 데이터 분석 업무를 하다 보면 &lt;b&gt;월별&lt;/b&gt;, &lt;b&gt;주별&lt;/b&gt;, &lt;b&gt;분기별&lt;/b&gt;, &lt;b&gt;연도별&lt;/b&gt;로 데이터를 집계해야 하는 일이 매우 많다. 이럴 때 사용할 수 있는 것이 바로 &lt;b&gt;기간 단위 추출 함수&lt;/b&gt;다. MySQL에서는 WEEK(), MONTH(), QUARTER(), YEARWEEK() 같은 강력한 함수들이 있어 날짜 기반 데이터를 쉽게 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvnH1M/btsPvEeFqH6/kXg3Pzs8V6HZtXGNxPiQ01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvnH1M/btsPvEeFqH6/kXg3Pzs8V6HZtXGNxPiQ01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvnH1M/btsPvEeFqH6/kXg3Pzs8V6HZtXGNxPiQ01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvnH1M%2FbtsPvEeFqH6%2FkXg3Pzs8V6HZtXGNxPiQ01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;490&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;507&quot; data-start=&quot;474&quot; data-ke-size=&quot;size26&quot;&gt;WEEK() 함수 - 주차(Week Number) 추출&lt;/h2&gt;
&lt;p data-end=&quot;590&quot; data-start=&quot;509&quot; data-ke-size=&quot;size16&quot;&gt;WEEK 함수는 날짜가 &lt;b&gt;1년 중 몇 번째 주(week number)&lt;/b&gt;에 속하는지를 반환한다. 기준일을 중심으로 주간 통계를 뽑을 때 유용하다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242338876&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT WEEK('2025-07-22');
-- 결과: 30 (30번째 주)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;714&quot; data-start=&quot;650&quot; data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;b&gt;일요일 시작 기준&lt;/b&gt;이며, 두 번째 인자로 &lt;b&gt;모드(mode)&lt;/b&gt;를 지정해 시작 요일을 바꿀 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;738&quot; data-start=&quot;716&quot; data-ke-size=&quot;size23&quot;&gt;예제: 모드 변경 (월요일 시작)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242344101&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT WEEK('2025-07-22', 1);
-- 결과: 30&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;836&quot; data-start=&quot;792&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 &lt;b&gt;월요일 시작 주차 집계&lt;/b&gt;가 필요할 경우 대부분 모드 1을 사용한다&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;865&quot; data-start=&quot;838&quot; data-ke-size=&quot;size26&quot;&gt;YEARWEEK() 함수 - 연도+주차 조합&lt;/h2&gt;
&lt;p data-end=&quot;944&quot; data-start=&quot;867&quot; data-ke-size=&quot;size16&quot;&gt;YEARWEEK는 연도와 주차를 합쳐서 YYYYWW 형태의 숫자를 반환한다. 예를 들어 2025년 30주차면 202530이 된다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242351756&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT YEARWEEK('2025-07-22');
-- 결과: 202530&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1075&quot; data-start=&quot;1003&quot; data-ke-size=&quot;size16&quot;&gt;이 방식은 &lt;b&gt;연도+주차로 정렬 가능&lt;/b&gt;하고, &lt;b&gt;범위 지정에도 유용&lt;/b&gt;하기 때문에 &lt;b&gt;주간 리포트&lt;/b&gt; 생성 시 아주 많이 쓰인다&lt;/p&gt;
&lt;h3 data-end=&quot;1094&quot; data-start=&quot;1077&quot; data-ke-size=&quot;size23&quot;&gt;예제: 최근 4주간 통계&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242360268&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT YEARWEEK(order_date) AS 년도_주차, COUNT(*) AS 건수
FROM orders
WHERE YEARWEEK(order_date) &amp;gt;= YEARWEEK(CURDATE()) - 4
GROUP BY 년도_주차
ORDER BY 년도_주차 DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1295&quot; data-start=&quot;1263&quot; data-ke-size=&quot;size16&quot;&gt;최근 4주간 주문 수를 주차 단위로 추출하는 실전형 쿼리다&lt;/p&gt;
&lt;h2 data-end=&quot;1317&quot; data-start=&quot;1297&quot; data-ke-size=&quot;size26&quot;&gt;MONTH() 함수 - 월 추출&lt;/h2&gt;
&lt;p data-end=&quot;1386&quot; data-start=&quot;1319&quot; data-ke-size=&quot;size16&quot;&gt;MONTH 함수는 날짜에서 &lt;b&gt;월(Month)&lt;/b&gt;만 정수 형태로 추출해준다. 월별 통계나 월별 분류 작업에 매우 유용하다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242365528&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT MONTH('2025-07-22');
-- 결과: 7&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1481&quot; data-start=&quot;1437&quot; data-ke-size=&quot;size16&quot;&gt;보통 YEAR()와 함께 조합해서 &lt;b&gt;연도+월 기준 통계&lt;/b&gt;로 많이 활용된다&lt;/p&gt;
&lt;h3 data-end=&quot;1499&quot; data-start=&quot;1483&quot; data-ke-size=&quot;size23&quot;&gt;예제: 월별 매출 집계&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242372975&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT YEAR(sale_date) AS 년도, MONTH(sale_date) AS 월, SUM(amount) AS 총매출
FROM sales
GROUP BY 년도, 월
ORDER BY 년도 DESC, 월 DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1667&quot; data-start=&quot;1637&quot; data-ke-size=&quot;size16&quot;&gt;이 쿼리는 리포트, BI 툴 연동 등에서 자주 활용된다&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1692&quot; data-start=&quot;1669&quot; data-ke-size=&quot;size26&quot;&gt;QUARTER() 함수 - 분기 추출&lt;/h2&gt;
&lt;p data-end=&quot;1752&quot; data-start=&quot;1694&quot; data-ke-size=&quot;size16&quot;&gt;QUARTER 함수는 해당 날짜가 &lt;b&gt;1분기, 2분기, 3분기, 4분기 중 어디에 속하는지&lt;/b&gt;를 반환한다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242379396&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT QUARTER('2025-07-22');
-- 결과: 3 (7월은 3분기)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1849&quot; data-start=&quot;1815&quot; data-ke-size=&quot;size16&quot;&gt;회계 리포트, 분기별 실적 보고서에 자주 등장하는 필수 함수다&lt;/p&gt;
&lt;h3 data-end=&quot;1867&quot; data-start=&quot;1851&quot; data-ke-size=&quot;size23&quot;&gt;예제: 분기별 주문 수&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242386613&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT YEAR(order_date) AS 년도, QUARTER(order_date) AS 분기, COUNT(*) AS 주문수
FROM orders
GROUP BY 년도, 분기
ORDER BY 년도, 분기;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2026&quot; data-start=&quot;2000&quot; data-ke-size=&quot;size26&quot;&gt;실무 팁: 날짜 + 기간 조합으로 정렬하기&lt;/h2&gt;
&lt;p data-end=&quot;2141&quot; data-start=&quot;2028&quot; data-ke-size=&quot;size16&quot;&gt;주차 기준 정렬이 필요한 경우 YEARWEEK(), 월 기준이면 YEAR() + MONTH() 조합, 분기 기준이면 YEAR() + QUARTER() 조합을 사용하는 것이 가장 깔끔하다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242393924&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CONCAT(YEAR(order_date), '-', LPAD(MONTH(order_date), 2, '0')) AS 월기준, COUNT(*) AS 건수
FROM orders
GROUP BY 월기준
ORDER BY 월기준;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2334&quot; data-start=&quot;2287&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 날짜가 월 단위로 정렬되면서 가독성도 좋고 BI 도구와의 연동도 수월하다&lt;/p&gt;
&lt;h2 data-end=&quot;2358&quot; data-start=&quot;2336&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 로그인 로그 주간 분포&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242401348&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT YEARWEEK(login_time) AS 주차, COUNT(*) AS 로그인수
FROM user_log
GROUP BY 주차
ORDER BY 주차 DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2507&quot; data-start=&quot;2468&quot; data-ke-size=&quot;size16&quot;&gt;사용자 활동 분석이나 주간 사용량 트렌드 분석에 자주 사용하는 패턴이다&lt;/p&gt;
&lt;h2 data-end=&quot;2514&quot; data-start=&quot;2509&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2709&quot; data-start=&quot;2516&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2546&quot; data-start=&quot;2516&quot;&gt;WEEK()은 1년 중 몇 번째 주인지 추출&lt;/li&gt;
&lt;li data-end=&quot;2592&quot; data-start=&quot;2547&quot;&gt;YEARWEEK()은 연도와 주차를 합친 값으로 주간 집계에 매우 유리&lt;/li&gt;
&lt;li data-end=&quot;2627&quot; data-start=&quot;2593&quot;&gt;MONTH()는 월 단위 추출로 월별 통계에서 필수&lt;/li&gt;
&lt;li data-end=&quot;2665&quot; data-start=&quot;2628&quot;&gt;QUARTER()는 분기별 통계, 회계 리포트 등에 적합&lt;/li&gt;
&lt;li data-end=&quot;2709&quot; data-start=&quot;2666&quot;&gt;연도와 함께 조합해서 사용하는 것이 실무에서 가장 일반적이고 확장성도 좋다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2719&quot; data-start=&quot;2711&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3066&quot; data-start=&quot;2721&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_week&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_week&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_month&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_month&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_quarter&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_quarter&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_yearweek&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_yearweek&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3168&quot; data-start=&quot;3084&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB데이터분석</category>
      <category>MYSQL</category>
      <category>MySQL집계함수</category>
      <category>mysql쿼리예제</category>
      <category>SQL리포트</category>
      <category>WEEK함수</category>
      <category>YEARWEEK</category>
      <category>기간단위추출</category>
      <category>분기별분석</category>
      <category>월별통계</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1053</guid>
      <comments>https://monkeybusiness.tistory.com/1053#entry1053comment</comments>
      <pubDate>Wed, 23 Jul 2025 16:47:23 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] STR_TO_DATE와 CAST를 활용한 문자열 &amp;rarr; 날짜 변환</title>
      <link>https://monkeybusiness.tistory.com/1052</link>
      <description>&lt;p data-end=&quot;479&quot; data-start=&quot;236&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 종종 '2025-07-22'처럼 날짜처럼 보이지만 실제로는 &lt;b&gt;문자열(String)&lt;/b&gt;로 저장된 데이터를 만나게 된다. 이 데이터를 진짜 날짜로 바꿔야 날짜 비교, 정렬, 필터링이 제대로 동작한다. 이때 가장 많이 쓰는 함수가 &lt;b&gt;STR_TO_DATE()&lt;/b&gt;이며, 간단한 경우에는 &lt;b&gt;CAST()&lt;/b&gt;로도 처리가 가능하다. 실무에서는 외부 엑셀 업로드, CSV 입력값, API 연동 데이터 처리에서 매우 자주 사용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vg3xF/btsPu9e2BU1/ia1ZIk4UGnZ5Q6tl9rMsg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vg3xF/btsPu9e2BU1/ia1ZIk4UGnZ5Q6tl9rMsg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vg3xF/btsPu9e2BU1/ia1ZIk4UGnZ5Q6tl9rMsg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVg3xF%2FbtsPu9e2BU1%2Fia1ZIk4UGnZ5Q6tl9rMsg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;502&quot; data-start=&quot;481&quot; data-ke-size=&quot;size26&quot;&gt;STR_TO_DATE() 함수란?&lt;/h2&gt;
&lt;p data-end=&quot;594&quot; data-start=&quot;504&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;STR_TO_DATE() 함수는 문자열을 날짜 또는 시간 형식으로 변환해주는 함수&lt;/b&gt;다. 내부적으로 포맷 문자열을 지정해서 원하는 형식으로 정확히 바꿔야 한다.&lt;/p&gt;
&lt;h3 data-end=&quot;605&quot; data-start=&quot;596&quot; data-ke-size=&quot;size23&quot;&gt;기본 문법&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242073700&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;STR_TO_DATE(string, format)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;683&quot; data-start=&quot;647&quot; data-ke-size=&quot;size16&quot;&gt;문자열과 해당 문자열의 포맷을 정확하게 지정해줘야 변환이 성공한다.&lt;/p&gt;
&lt;h3 data-end=&quot;701&quot; data-start=&quot;685&quot; data-ke-size=&quot;size23&quot;&gt;예제: 기본 날짜 변환&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242078845&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('2025-07-22', '%Y-%m-%d');
-- 결과: 2025-07-22 (DATE 형식)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;848&quot; data-start=&quot;789&quot; data-ke-size=&quot;size16&quot;&gt;이제 '2025-07-22'는 문자열이 아닌 날짜로 처리되므로 조건 비교, 정렬, 필터링에 문제가 없다&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;866&quot; data-start=&quot;850&quot; data-ke-size=&quot;size26&quot;&gt;자주 사용하는 포맷 코드&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1261&quot; data-start=&quot;868&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;코드&lt;/td&gt;
&lt;td&gt;의미&lt;/td&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;983&quot; data-start=&quot;946&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;954&quot; data-start=&quot;946&quot;&gt;%Y&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;965&quot; data-start=&quot;954&quot;&gt;4자리 연도&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;983&quot; data-start=&quot;965&quot;&gt;2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1021&quot; data-start=&quot;984&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;992&quot; data-start=&quot;984&quot;&gt;%y&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1003&quot; data-start=&quot;992&quot;&gt;2자리 연도&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1021&quot; data-start=&quot;1003&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1060&quot; data-start=&quot;1022&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1030&quot; data-start=&quot;1022&quot;&gt;%m&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1042&quot; data-start=&quot;1030&quot;&gt;2자리 월&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1060&quot; data-start=&quot;1042&quot;&gt;07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1099&quot; data-start=&quot;1061&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1069&quot; data-start=&quot;1061&quot;&gt;%d&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1081&quot; data-start=&quot;1069&quot;&gt;2자리 일&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1099&quot; data-start=&quot;1081&quot;&gt;22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1137&quot; data-start=&quot;1100&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1108&quot; data-start=&quot;1100&quot;&gt;%H&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1119&quot; data-start=&quot;1108&quot;&gt;24시간제 시&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1137&quot; data-start=&quot;1119&quot;&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1178&quot; data-start=&quot;1138&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1146&quot; data-start=&quot;1138&quot;&gt;%i&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1160&quot; data-start=&quot;1146&quot;&gt;분&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1178&quot; data-start=&quot;1160&quot;&gt;45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1219&quot; data-start=&quot;1179&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1187&quot; data-start=&quot;1179&quot;&gt;%s&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1201&quot; data-start=&quot;1187&quot;&gt;초&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1219&quot; data-start=&quot;1201&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1261&quot; data-start=&quot;1220&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1228&quot; data-start=&quot;1220&quot;&gt;%p&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1243&quot; data-start=&quot;1228&quot;&gt;AM/PM&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1261&quot; data-start=&quot;1243&quot;&gt;AM, PM&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1280&quot; data-start=&quot;1263&quot; data-ke-size=&quot;size26&quot;&gt;예제: 날짜 + 시간 변환&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242103148&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('2025-07-22 14:30:00', '%Y-%m-%d %H:%i:%s');
-- 결과: 2025-07-22 14:30:00&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1450&quot; data-start=&quot;1385&quot; data-ke-size=&quot;size16&quot;&gt;이제 DATETIME으로 바뀌었기 때문에 NOW(), CURDATE() 같은 시스템 시간과 직접 비교 가능하다&lt;/p&gt;
&lt;h2 data-end=&quot;1478&quot; data-start=&quot;1452&quot; data-ke-size=&quot;size26&quot;&gt;예제: 사용자 입력값 처리 (엑셀/CSV)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242108100&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE(user_input, '%d/%m/%Y') AS 표준형_날짜
FROM uploads;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1625&quot; data-start=&quot;1559&quot; data-ke-size=&quot;size16&quot;&gt;사용자가 22/07/2025처럼 &lt;b&gt;영국식 또는 비표준 포맷&lt;/b&gt;으로 입력한 데이터를 표준 DATE 형식으로 바꿔준다&lt;/p&gt;
&lt;h2 data-end=&quot;1646&quot; data-start=&quot;1627&quot; data-ke-size=&quot;size26&quot;&gt;예제: 요일 포함된 포맷 처리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242113012&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STR_TO_DATE('Tuesday 2025-07-22', '%W %Y-%m-%d');
-- 결과: 2025-07-22&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1769&quot; data-start=&quot;1735&quot; data-ke-size=&quot;size16&quot;&gt;%W를 활용해 요일 정보가 포함된 문자열도 처리할 수 있다&lt;/p&gt;
&lt;h2 data-end=&quot;1794&quot; data-start=&quot;1771&quot; data-ke-size=&quot;size26&quot;&gt;CAST()로 간단하게 날짜 변환하기&lt;/h2&gt;
&lt;p data-end=&quot;1894&quot; data-start=&quot;1796&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CAST() 함수는 문자열을 명시적으로 다른 데이터 타입으로 바꿔주는 MySQL의 표준 SQL 문법 함수&lt;/b&gt;다. 날짜 포맷이 MySQL 내부 기본 포맷일 때만 사용 가능하다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242119964&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAST('2025-07-22' AS DATE);
-- 결과: 2025-07-22&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2036&quot; data-start=&quot;1961&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 간단한 형식이면 STR_TO_DATE() 대신 사용할 수 있다. 하지만 복잡한 포맷에서는 CAST()로 변환이 불가능하다&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2057&quot; data-start=&quot;2038&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 문자열 날짜 비교&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242127341&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM events
WHERE STR_TO_DATE(event_date_text, '%Y%m%d') &amp;gt;= CURDATE();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2246&quot; data-start=&quot;2151&quot; data-ke-size=&quot;size16&quot;&gt;'20250722'처럼 붙어 있는 날짜 문자열을 DATE로 바꿔 오늘 날짜와 비교한다. 이처럼 STR_TO_DATE()는 &lt;b&gt;데이터 클렌징 필수 함수&lt;/b&gt;로 활용된다&lt;/p&gt;
&lt;h2 data-end=&quot;2267&quot; data-start=&quot;2248&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 시간 비교 필터링&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753242133692&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM logs
WHERE STR_TO_DATE(log_time_str, '%H:%i:%s') BETWEEN '09:00:00' AND '18:00:00';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2446&quot; data-start=&quot;2379&quot; data-ke-size=&quot;size16&quot;&gt;로그에서 '14:25:30'과 같은 문자열 시간을 TIME 형식으로 바꾸고, 근무 시간대 필터링에 활용할 수 있다&lt;/p&gt;
&lt;h2 data-end=&quot;2472&quot; data-start=&quot;2448&quot; data-ke-size=&quot;size26&quot;&gt;STR_TO_DATE 사용 시 주의사항&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2644&quot; data-start=&quot;2474&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2529&quot; data-start=&quot;2474&quot;&gt;포맷 문자열이 실제 데이터와 완벽히 일치해야 한다. 한 글자라도 다르면 NULL 반환됨&lt;/li&gt;
&lt;li data-end=&quot;2594&quot; data-start=&quot;2530&quot;&gt;변환 실패시 오류 없이 NULL로 처리되므로, 실무에서는 IS NULL 조건으로 실패 데이터 추출 가능&lt;/li&gt;
&lt;li data-end=&quot;2644&quot; data-start=&quot;2595&quot;&gt;문자열 데이터가 비정형이면 사전 가공 또는 정규식으로 정리한 후 적용하는 것이 좋다&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-end=&quot;2673&quot; data-start=&quot;2646&quot; data-ke-size=&quot;size26&quot;&gt;언제 STR_TO_DATE, 언제 CAST?&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2943&quot; data-start=&quot;2675&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;조건&lt;/td&gt;
&lt;td&gt;추천 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2809&quot; data-start=&quot;2767&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2791&quot; data-start=&quot;2767&quot;&gt;포맷이 복잡함&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2809&quot; data-start=&quot;2791&quot;&gt;STR_TO_DATE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2862&quot; data-start=&quot;2810&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2833&quot; data-start=&quot;2810&quot;&gt;문자열 형식이 yyyy-mm-dd임&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2862&quot; data-start=&quot;2833&quot;&gt;CAST 또는 STR_TO_DATE 모두 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2902&quot; data-start=&quot;2863&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2884&quot; data-start=&quot;2863&quot;&gt;날짜+시간 조합 문자열&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2902&quot; data-start=&quot;2884&quot;&gt;STR_TO_DATE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2943&quot; data-start=&quot;2903&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2925&quot; data-start=&quot;2903&quot;&gt;엑셀/CSV 외부 입력 처리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2943&quot; data-start=&quot;2925&quot;&gt;STR_TO_DATE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 형식이면 CAST도 가능하지만, 실무에서는 거의 항상 STR_TO_DATE가 안정적&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;3007&quot; data-start=&quot;3002&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3226&quot; data-start=&quot;3009&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3066&quot; data-start=&quot;3009&quot;&gt;STR_TO_DATE()는 문자열을 날짜 또는 시간으로 변환할 때 사용하는 MySQL 함수다&lt;/li&gt;
&lt;li data-end=&quot;3116&quot; data-start=&quot;3067&quot;&gt;포맷 문자열을 정확하게 지정해야 정상 변환되며, 형식이 다르면 NULL을 반환한다&lt;/li&gt;
&lt;li data-end=&quot;3169&quot; data-start=&quot;3117&quot;&gt;CAST()는 내부 기본 포맷(YYYY-MM-DD)일 때만 간단하게 쓸 수 있다&lt;/li&gt;
&lt;li data-end=&quot;3226&quot; data-start=&quot;3170&quot;&gt;외부 데이터 정제, API 파싱, 조건 비교 등에서 STR_TO_DATE는 매우 자주 사용된다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;3236&quot; data-start=&quot;3228&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3403&quot; data-start=&quot;3238&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_str-to-date&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_str-to-date&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3513&quot; data-start=&quot;3421&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>cast함수</category>
      <category>CSV날짜변환</category>
      <category>DB실무팁</category>
      <category>MYSQL</category>
      <category>MySQL날짜처리</category>
      <category>MySQL시간함수</category>
      <category>SQL문자열변환</category>
      <category>strtodate</category>
      <category>문자열날짜변환</category>
      <category>엑셀업로드SQL</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1052</guid>
      <comments>https://monkeybusiness.tistory.com/1052#entry1052comment</comments>
      <pubDate>Wed, 23 Jul 2025 15:43:15 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] UNIX_TIMESTAMP, FROM_UNIXTIME 변환 함수 정리  </title>
      <link>https://monkeybusiness.tistory.com/1051</link>
      <description>&lt;p data-end=&quot;446&quot; data-start=&quot;240&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 &lt;b&gt;날짜를 숫자로&lt;/b&gt;, 혹은 숫자를 다시 날짜로 변환해야 할 때 가장 강력한 도구가 바로 &lt;b&gt;UNIX_TIMESTAMP&lt;/b&gt;와 &lt;b&gt;FROM_UNIXTIME&lt;/b&gt; 함수이다. 특히 서버 로그나 외부 API 데이터에서 유닉스 타임스탬프를 사용하는 경우, 이 함수들의 활용은 필수적이다. 실무에서는 로그 분석, 시간 비교, 외부 데이터 연동에서 빠지지 않고 등장한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XDsV5/btsPtW866oN/bzA036A9No7LEfVa0eXI4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XDsV5/btsPtW866oN/bzA036A9No7LEfVa0eXI4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XDsV5/btsPtW866oN/bzA036A9No7LEfVa0eXI4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXDsV5%2FbtsPtW866oN%2FbzA036A9No7LEfVa0eXI4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;472&quot; data-start=&quot;448&quot; data-ke-size=&quot;size26&quot;&gt;UNIX_TIMESTAMP() 함수란?&lt;/h2&gt;
&lt;p data-end=&quot;582&quot; data-start=&quot;474&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UNIX_TIMESTAMP() 함수는 날짜/시간을 유닉스 타임스탬프(초 단위 정수)로 변환&lt;/b&gt;해준다. 유닉스 타임스탬프는 1970년 1월 1일 00:00:00 UTC부터의 경과 초를 의미한다.&lt;/p&gt;
&lt;h3 data-end=&quot;593&quot; data-start=&quot;584&quot; data-ke-size=&quot;size23&quot;&gt;기본 문법&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241881788&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UNIX_TIMESTAMP([datetime])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;701&quot; data-start=&quot;634&quot; data-ke-size=&quot;size16&quot;&gt;괄호 없이 사용하면 현재 시간을 기준으로 반환한다. 괄호 안에 날짜 값을 넣으면 해당 시간의 유닉스 타임스탬프를 반환한다&lt;/p&gt;
&lt;h3 data-end=&quot;727&quot; data-start=&quot;703&quot; data-ke-size=&quot;size23&quot;&gt;예제: 현재 유닉스 타임스탬프 구하기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241888092&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT UNIX_TIMESTAMP();
-- 결과: 1753173471 (예시)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;813&quot; data-start=&quot;789&quot; data-ke-size=&quot;size23&quot;&gt;예제: 특정 날짜를 타임스탬프로 변환&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241894156&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT UNIX_TIMESTAMP('2025-07-22 12:00:00');
-- 결과: 1753168800&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;931&quot; data-start=&quot;891&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 원하는 날짜를 초 단위 숫자로 바꿔 다른 시스템과 연동할 수 있다&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;956&quot; data-start=&quot;933&quot; data-ke-size=&quot;size26&quot;&gt;FROM_UNIXTIME() 함수란?&lt;/h2&gt;
&lt;p data-end=&quot;1027&quot; data-start=&quot;958&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FROM_UNIXTIME() 함수는 유닉스 타임스탬프 값을 사람이 읽을 수 있는 날짜/시간 형식으로 변환&lt;/b&gt;해주는 함수다&lt;/p&gt;
&lt;h3 data-end=&quot;1038&quot; data-start=&quot;1029&quot; data-ke-size=&quot;size23&quot;&gt;기본 문법&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241901901&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM_UNIXTIME(unix_timestamp [, format])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1146&quot; data-start=&quot;1093&quot; data-ke-size=&quot;size16&quot;&gt;두 번째 인자에 DATE_FORMAT 스타일 포맷을 지정하면 원하는 형식으로 출력할 수 있다&lt;/p&gt;
&lt;h3 data-end=&quot;1173&quot; data-start=&quot;1148&quot; data-ke-size=&quot;size23&quot;&gt;예제: 유닉스 타임스탬프를 날짜로 변환&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241907564&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FROM_UNIXTIME(1753168800);
-- 결과: 2025-07-22 12:00:00&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1261&quot; data-start=&quot;1248&quot; data-ke-size=&quot;size23&quot;&gt;예제: 포맷 지정&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;pre id=&quot;code_1753241919732&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FROM_UNIXTIME(1753168800, '%Y-%m-%d %H시 %i분');
-- 결과: 2025-07-22 12시 00분&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1378&quot; data-start=&quot;1355&quot; data-ke-size=&quot;size16&quot;&gt;한국형 표현으로 보기 좋게 바꿀 수도 있다&lt;/p&gt;
&lt;h2 data-end=&quot;1406&quot; data-start=&quot;1380&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: 로그 테이블에 타임스탬프 저장&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241927284&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO log_table (event_type, created_at)
VALUES ('LOGIN_SUCCESS', UNIX_TIMESTAMP());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1563&quot; data-start=&quot;1511&quot; data-ke-size=&quot;size16&quot;&gt;로그 테이블에 현재 시각을 유닉스 정수로 저장해두면, 용량이 작고 비교가 빠르다는 장점이 있다&lt;/p&gt;
&lt;h2 data-end=&quot;1588&quot; data-start=&quot;1565&quot; data-ke-size=&quot;size26&quot;&gt;실무 예제: API 응답 데이터 변환&lt;/h2&gt;
&lt;p data-end=&quot;1649&quot; data-start=&quot;1590&quot; data-ke-size=&quot;size16&quot;&gt;외부 API에서 timestamp: 1753168800 같은 값을 받을 때 바로 날짜로 변환할 수 있다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241934652&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FROM_UNIXTIME(api_response_time) AS 응답시각
FROM external_data;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1772&quot; data-start=&quot;1731&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 사람에게 익숙한 날짜로 화면 출력이나 보고서를 구성할 수 있다&lt;/p&gt;
&lt;h2 data-end=&quot;1795&quot; data-start=&quot;1774&quot; data-ke-size=&quot;size26&quot;&gt;시간 정렬 및 비교에 적합한 이유&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1985&quot; data-start=&quot;1797&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1845&quot; data-start=&quot;1797&quot;&gt;UNIX_TIMESTAMP는 &lt;b&gt;정렬 성능이 좋고 범위 조건 처리도 빠르다&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1899&quot; data-start=&quot;1846&quot;&gt;BETWEEN 등 조건절에서 초 단위 비교가 가능해 &lt;b&gt;정밀한 시간 비교&lt;/b&gt;가 가능하다&lt;/li&gt;
&lt;li data-end=&quot;1985&quot; data-start=&quot;1900&quot;&gt;타임스탬프는 다양한 언어(JavaScript, Python, PHP 등)에서도 공통으로 쓰이므로 &lt;b&gt;언어 간 시간 처리에 가장 안정적인 방식&lt;/b&gt;이다&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2008&quot; data-start=&quot;1987&quot; data-ke-size=&quot;size26&quot;&gt;예제: 24시간 이내 데이터 조회&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241945211&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM messages
WHERE UNIX_TIMESTAMP(created_at) &amp;gt;= UNIX_TIMESTAMP() - 86400;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2152&quot; data-start=&quot;2107&quot; data-ke-size=&quot;size16&quot;&gt;현재 시각 기준으로 24시간(86400초) 이내에 생성된 메시지만 조회할 수 있다&lt;/p&gt;
&lt;h2 data-end=&quot;2161&quot; data-start=&quot;2154&quot; data-ke-size=&quot;size26&quot;&gt;주의사항&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2407&quot; data-start=&quot;2163&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2240&quot; data-start=&quot;2163&quot;&gt;MySQL 서버의 &lt;b&gt;타임존 설정에 따라 결과가 달라질 수 있다&lt;/b&gt;&lt;br /&gt;타임존이 UTC면 한국 시간보다 9시간 느릴 수 있음&lt;/li&gt;
&lt;li data-end=&quot;2340&quot; data-start=&quot;2241&quot;&gt;UNIX_TIMESTAMP()는 DATETIME, DATE, TIMESTAMP에 모두 적용 가능하지만, 시간 없는 DATE는 00:00:00으로 처리됨&lt;/li&gt;
&lt;li data-end=&quot;2407&quot; data-start=&quot;2341&quot;&gt;FROM_UNIXTIME()는 반환값이 DATETIME이고, 포맷을 지정하면 문자열(String)로 변환됨&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-end=&quot;2419&quot; data-start=&quot;2409&quot; data-ke-size=&quot;size26&quot;&gt;포맷 조합 팁&lt;/h2&gt;
&lt;p data-end=&quot;2483&quot; data-start=&quot;2421&quot; data-ke-size=&quot;size16&quot;&gt;FROM_UNIXTIME에서 사용할 수 있는 포맷은 DATE_FORMAT과 동일하다. 아래는 자주 쓰는 조합이다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241953084&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT FROM_UNIXTIME(1753168800, '%Y-%m-%d %H:%i:%s');
SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(), '%Y년 %m월 %d일 %H시 %i분');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2659&quot; data-start=&quot;2615&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 실시간 변환도 가능하며, &lt;b&gt;양방향 변환이 가능한 핵심 함수 조합&lt;/b&gt;이다&lt;/p&gt;
&lt;h2 data-end=&quot;2666&quot; data-start=&quot;2661&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2863&quot; data-start=&quot;2668&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2711&quot; data-start=&quot;2668&quot;&gt;UNIX_TIMESTAMP()는 날짜를 정수형 초 단위로 변환해준다&lt;/li&gt;
&lt;li data-end=&quot;2772&quot; data-start=&quot;2712&quot;&gt;FROM_UNIXTIME()는 정수형 유닉스 타임스탬프를 다시 사람이 읽는 날짜 형식으로 바꿔준다&lt;/li&gt;
&lt;li data-end=&quot;2819&quot; data-start=&quot;2773&quot;&gt;외부 API 연동, 시간 기반 정렬, 로그 데이터 처리에 매우 자주 사용된다&lt;/li&gt;
&lt;li data-end=&quot;2863&quot; data-start=&quot;2820&quot;&gt;DATE_FORMAT()과 함께 사용하면 자유로운 포맷 출력도 가능하다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2873&quot; data-start=&quot;2865&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3061&quot; data-start=&quot;2875&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_unix-timestamp&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_unix-timestamp&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_from-unixtime&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_from-unixtime&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3176&quot; data-start=&quot;3079&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>DB시간계산</category>
      <category>from_unixtime</category>
      <category>MYSQL</category>
      <category>mysql날짜함수</category>
      <category>MySQL함수정리</category>
      <category>SQL시간변환</category>
      <category>UNIX_TIMESTAMP</category>
      <category>로그처리</category>
      <category>웹개발팁</category>
      <category>타임스탬프변환</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1051</guid>
      <comments>https://monkeybusiness.tistory.com/1051#entry1051comment</comments>
      <pubDate>Wed, 23 Jul 2025 14:40:04 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] ADDDATE, SUBDATE, DATE_ADD, DATE_SUB 활용법  </title>
      <link>https://monkeybusiness.tistory.com/1050</link>
      <description>&lt;p data-end=&quot;525&quot; data-start=&quot;290&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 날짜를 기준으로 &lt;b&gt;며칠 뒤&lt;/b&gt; 또는 &lt;b&gt;며칠 전&lt;/b&gt;의 날짜를 구해야 하는 경우가 많다. 예를 들어 &amp;ldquo;회원가입일 + 7일 뒤&amp;rdquo;에 알림을 보내거나, &amp;ldquo;오늘로부터 30일 전&amp;rdquo; 데이터를 조회할 때 사용할 수 있는 함수가 바로 &lt;b&gt;ADDDATE, SUBDATE, DATE_ADD, DATE_SUB&lt;/b&gt;이다. 이 네 가지 함수는 기능상 거의 같지만 &lt;b&gt;표현 방식과 문법 차이&lt;/b&gt;가 있어 용도에 맞게 쓰는 것이 중요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmdkqg/btsPuoYlWYk/bmmwN6wN6iFoI5CVJv1kB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmdkqg/btsPuoYlWYk/bmmwN6wN6iFoI5CVJv1kB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmdkqg/btsPuoYlWYk/bmmwN6wN6iFoI5CVJv1kB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmdkqg%2FbtsPuoYlWYk%2FbmmwN6wN6iFoI5CVJv1kB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;551&quot; data-start=&quot;527&quot; data-ke-size=&quot;size26&quot;&gt;ADDDATE() 함수 - 날짜 더하기&lt;/h2&gt;
&lt;p data-end=&quot;595&quot; data-start=&quot;553&quot; data-ke-size=&quot;size16&quot;&gt;ADDDATE는 &lt;b&gt;날짜를 기준으로 일수 또는 시간 단위를 더하는 함수&lt;/b&gt;다&lt;/p&gt;
&lt;h3 data-end=&quot;606&quot; data-start=&quot;597&quot; data-ke-size=&quot;size23&quot;&gt;기본 문법&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241409092&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ADDDATE(date, INTERVAL n unit)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;667&quot; data-start=&quot;651&quot; data-ke-size=&quot;size16&quot;&gt;또는 더 짧은 문법도 가능하다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241414868&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ADDDATE(date, days)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;723&quot; data-start=&quot;701&quot; data-ke-size=&quot;size23&quot;&gt;예제: 가입일 기준 7일 뒤 알림&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241439540&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT user_name,
       ADDDATE(join_date, INTERVAL 7 DAY) AS 알림일자
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;829&quot; data-start=&quot;817&quot; data-ke-size=&quot;size16&quot;&gt;또는 이렇게도 가능하다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241444820&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ADDDATE('2025-07-01', 10);
-- 결과: 2025-07-11&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;921&quot; data-start=&quot;895&quot; data-ke-size=&quot;size16&quot;&gt;숫자만 넣는 경우 기본 단위는 DAY로 처리된다&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;946&quot; data-start=&quot;923&quot; data-ke-size=&quot;size26&quot;&gt;SUBDATE() 함수 - 날짜 빼기&lt;/h2&gt;
&lt;p data-end=&quot;1000&quot; data-start=&quot;948&quot; data-ke-size=&quot;size16&quot;&gt;SUBDATE는 &lt;b&gt;기준일로부터 날짜를 빼는 함수&lt;/b&gt;다. 즉, 과거 날짜를 계산할 때 사용된다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241453140&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT SUBDATE('2025-07-22', INTERVAL 5 DAY);
-- 결과: 2025-07-17&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1104&quot; data-start=&quot;1078&quot; data-ke-size=&quot;size23&quot;&gt;예제: 30일 이내 로그인한 사용자 찾기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241459356&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM users
WHERE last_login &amp;gt;= SUBDATE(CURDATE(), INTERVAL 30 DAY);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1246&quot; data-start=&quot;1195&quot; data-ke-size=&quot;size16&quot;&gt;오늘로부터 30일 이내에 로그인한 사용자만 조회된다. 날짜를 &amp;ldquo;빼는&amp;rdquo; 연산으로 범위를 만든다&lt;/p&gt;
&lt;h2 data-end=&quot;1281&quot; data-start=&quot;1248&quot; data-ke-size=&quot;size26&quot;&gt;DATE_ADD() 함수 - 날짜 더하기 (표준 표기)&lt;/h2&gt;
&lt;p data-end=&quot;1339&quot; data-start=&quot;1283&quot; data-ke-size=&quot;size16&quot;&gt;DATE_ADD는 기능상 ADDDATE와 동일하지만, &lt;b&gt;좀 더 명시적이고 표준적인 표현 방식&lt;/b&gt;이다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241466524&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_ADD('2025-07-01', INTERVAL 10 DAY);
-- 결과: 2025-07-11&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1436&quot; data-start=&quot;1419&quot; data-ke-size=&quot;size23&quot;&gt;예제: 배송 예정일 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241472628&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT order_id,
       DATE_ADD(order_date, INTERVAL 3 DAY) AS 예상_배송일
FROM orders;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1570&quot; data-start=&quot;1534&quot; data-ke-size=&quot;size16&quot;&gt;주문일 기준으로 3일 뒤를 계산하여 배송 예정일을 산출할 수 있다&lt;/p&gt;
&lt;h2 data-end=&quot;1604&quot; data-start=&quot;1572&quot; data-ke-size=&quot;size26&quot;&gt;DATE_SUB() 함수 - 날짜 빼기 (표준 표기)&lt;/h2&gt;
&lt;p data-end=&quot;1662&quot; data-start=&quot;1606&quot; data-ke-size=&quot;size16&quot;&gt;DATE_SUB는 SUBDATE와 같지만, 역시 &lt;b&gt;표현이 더 명시적&lt;/b&gt;이며 많은 개발자들이 선호한다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241482388&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_SUB('2025-07-22', INTERVAL 15 DAY);
-- 결과: 2025-07-07&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1764&quot; data-start=&quot;1742&quot; data-ke-size=&quot;size23&quot;&gt;예제: 지난달부터 누적 주문 조회&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241488292&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM orders
WHERE order_date &amp;gt;= DATE_SUB(CURDATE(), INTERVAL 1 MONTH);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1894&quot; data-start=&quot;1858&quot; data-ke-size=&quot;size16&quot;&gt;현재 날짜로부터 한 달 전부터 오늘까지의 데이터를 추출할 수 있다&lt;/p&gt;
&lt;h2 data-end=&quot;1909&quot; data-start=&quot;1896&quot; data-ke-size=&quot;size26&quot;&gt;지원되는 시간 단위&lt;/h2&gt;
&lt;p data-end=&quot;1946&quot; data-start=&quot;1911&quot; data-ke-size=&quot;size16&quot;&gt;모든 ADD/SUB 함수에서 아래와 같은 단위를 사용할 수 있다&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2292&quot; data-start=&quot;1948&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;단위&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2050&quot; data-start=&quot;2016&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2031&quot; data-start=&quot;2016&quot;&gt;SECOND&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2050&quot; data-start=&quot;2031&quot;&gt;초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2085&quot; data-start=&quot;2051&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2066&quot; data-start=&quot;2051&quot;&gt;MINUTE&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2085&quot; data-start=&quot;2066&quot;&gt;분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2119&quot; data-start=&quot;2086&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2101&quot; data-start=&quot;2086&quot;&gt;HOUR&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2119&quot; data-start=&quot;2101&quot;&gt;시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2154&quot; data-start=&quot;2120&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2135&quot; data-start=&quot;2120&quot;&gt;DAY&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2154&quot; data-start=&quot;2135&quot;&gt;일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2189&quot; data-start=&quot;2155&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2170&quot; data-start=&quot;2155&quot;&gt;WEEK&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2189&quot; data-start=&quot;2170&quot;&gt;주&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2224&quot; data-start=&quot;2190&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2205&quot; data-start=&quot;2190&quot;&gt;MONTH&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2224&quot; data-start=&quot;2205&quot;&gt;월&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2258&quot; data-start=&quot;2225&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2240&quot; data-start=&quot;2225&quot;&gt;QUARTER&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2258&quot; data-start=&quot;2240&quot;&gt;분기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2292&quot; data-start=&quot;2259&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2274&quot; data-start=&quot;2259&quot;&gt;YEAR&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2292&quot; data-start=&quot;2274&quot;&gt;연도&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2304&quot; data-start=&quot;2294&quot; data-ke-size=&quot;size16&quot;&gt;예: 1시간 더하기&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241511148&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_ADD('2025-07-22 12:00:00', INTERVAL 1 HOUR);
-- 결과: 2025-07-22 13:00:00&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9015116241126433&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2414&quot; data-start=&quot;2402&quot; data-ke-size=&quot;size26&quot;&gt;복합 단위 사용법&lt;/h2&gt;
&lt;p data-end=&quot;2475&quot; data-start=&quot;2416&quot; data-ke-size=&quot;size16&quot;&gt;복수 단위를 조합해서 사용하는 것도 가능하다. 단, &lt;b&gt;INTERVAL 뒤에 복합 문자열&lt;/b&gt;로 넣어야 한다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241520751&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_ADD('2025-07-01', INTERVAL '2 3' DAY_HOUR);
-- 결과: 2025-07-03 03:00:00&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2598&quot; data-start=&quot;2572&quot; data-ke-size=&quot;size16&quot;&gt;여기서 &amp;lsquo;2일 3시간&amp;rsquo;을 한꺼번에 더할 수 있다&lt;/p&gt;
&lt;h2 data-end=&quot;2611&quot; data-start=&quot;2600&quot; data-ke-size=&quot;size26&quot;&gt;실무 활용 예제&lt;/h2&gt;
&lt;h3 data-end=&quot;2632&quot; data-start=&quot;2613&quot; data-ke-size=&quot;size23&quot;&gt;예제: 유효기간 만료일 계산&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241527580&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT user_id,
       DATE_ADD(issued_at, INTERVAL 1 YEAR) AS 만료일자
FROM certificates;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2766&quot; data-start=&quot;2733&quot; data-ke-size=&quot;size16&quot;&gt;인증서 발급일 기준 1년 뒤 만료일자를 계산하는 실전 예제다&lt;/p&gt;
&lt;h3 data-end=&quot;2788&quot; data-start=&quot;2768&quot; data-ke-size=&quot;size23&quot;&gt;예제: 일주일 이내 주문 통계&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753241535764&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT COUNT(*) AS 최근7일주문수
FROM orders
WHERE order_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND CURDATE();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2963&quot; data-start=&quot;2917&quot; data-ke-size=&quot;size16&quot;&gt;최근 일주일 동안 발생한 주문 수를 추출하는 쿼리로, 실시간 리포트에 자주 활용된다&lt;/p&gt;
&lt;h2 data-end=&quot;2981&quot; data-start=&quot;2965&quot; data-ke-size=&quot;size26&quot;&gt;어떤 함수를 써야 할까?&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;3302&quot; data-start=&quot;2983&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수&lt;/td&gt;
&lt;td&gt;의미&lt;/td&gt;
&lt;td&gt;특징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3152&quot; data-start=&quot;3103&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3116&quot; data-start=&quot;3103&quot;&gt;ADDDATE&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3132&quot; data-start=&quot;3116&quot;&gt;날짜 더하기&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3152&quot; data-start=&quot;3132&quot;&gt;간결한 문법, DAY만 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3203&quot; data-start=&quot;3153&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3166&quot; data-start=&quot;3153&quot;&gt;SUBDATE&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3183&quot; data-start=&quot;3166&quot;&gt;날짜 빼기&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3203&quot; data-start=&quot;3183&quot;&gt;간결한 문법, DAY만 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3252&quot; data-start=&quot;3204&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3217&quot; data-start=&quot;3204&quot;&gt;DATE_ADD&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3233&quot; data-start=&quot;3217&quot;&gt;날짜 더하기&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3252&quot; data-start=&quot;3233&quot;&gt;표준 문법, 다양한 단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3302&quot; data-start=&quot;3253&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3266&quot; data-start=&quot;3253&quot;&gt;DATE_SUB&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3283&quot; data-start=&quot;3266&quot;&gt;날짜 빼기&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3302&quot; data-start=&quot;3283&quot;&gt;표준 문법, 다양한 단위&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3397&quot; data-start=&quot;3304&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;표준성과 확장성&lt;/b&gt;을 중시한다면 DATE_ADD, DATE_SUB를 추천한다. &lt;b&gt;간단한 일수 연산&lt;/b&gt;이라면 ADDDATE, SUBDATE도 충분하다&lt;/p&gt;
&lt;h2 data-end=&quot;3404&quot; data-start=&quot;3399&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3642&quot; data-start=&quot;3406&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3491&quot; data-start=&quot;3406&quot;&gt;날짜에 일수, 월수, 연도 등을 더하거나 빼야 할 때는 ADDDATE, DATE_ADD, SUBDATE, DATE_SUB를 활용한다&lt;/li&gt;
&lt;li data-end=&quot;3543&quot; data-start=&quot;3492&quot;&gt;INTERVAL n unit 문법은 일관되게 사용되며 다양한 단위 지원이 가능하다&lt;/li&gt;
&lt;li data-end=&quot;3596&quot; data-start=&quot;3544&quot;&gt;실무에서는 회원 유효기간, 리포트 조회범위, 자동 알림 스케줄 등 다양한 곳에 응용된다&lt;/li&gt;
&lt;li data-end=&quot;3642&quot; data-start=&quot;3597&quot;&gt;DATE_ADD, DATE_SUB는 더 명확하고 범용성이 높아 추천된다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;3652&quot; data-start=&quot;3644&quot; data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-end=&quot;3829&quot; data-start=&quot;3654&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-sub&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-sub&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;3933&quot; data-start=&quot;3847&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>ADDDATE</category>
      <category>DateAdd</category>
      <category>DATESUB</category>
      <category>DB날짜연산</category>
      <category>MYSQL</category>
      <category>mysql날짜함수</category>
      <category>mysql쿼리예제</category>
      <category>SQL리포트</category>
      <category>SUBDATE</category>
      <category>날짜계산</category>
      <author>인생아</author>
      <guid isPermaLink="true">https://monkeybusiness.tistory.com/1050</guid>
      <comments>https://monkeybusiness.tistory.com/1050#entry1050comment</comments>
      <pubDate>Wed, 23 Jul 2025 13:37:03 +0900</pubDate>
    </item>
  </channel>
</rss>