Post

๐Ÿ—‚๏ธ P6Spy SQL Logging

๐Ÿ—‚๏ธ P6Spy SQL Logging

P6Spy ๋„์ž… ๊ทผ๊ฑฐ

  • ์ฝ”๋“œ์—์„œ DB ์ ‘๊ทผ ์‹œ SQL๋ฌธ์ด ์˜ˆ์ƒ๋Œ€๋กœ ์‹คํ–‰๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•จ
    1. WHERE ์กฐ๊ฑด์— ์˜ˆ์ƒํ•œ ๊ฐ’์ด ๋“ค์–ด๊ฐ”๋Š”์ง€
    2. Lazy Loading์ด ์˜ˆ์ƒ์น˜ ์•Š๊ฒŒ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐœ์ƒํ–ˆ๋Š”์ง€(N+1)
    3. ํŠน์ • ์กฐํšŒ๊ฐ€ ๋„ˆ๋ฌด ๋А๋ฆฐ ๊ฑด ์•„๋‹Œ์ง€

์˜์กด์„ฑ ์ฃผ์ž…

1
2
/* p6spy */
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'
  • Spring Boot 3.0.0 ์ด์ƒ์€ 1.9.0 ์ดํ›„ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.ย 
1
2
3
2025-03-06T00:08:48.284+09:00ย ย INFO 8720 --- [nio-8080-exec-6] p6spyย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย : #1741187328284 | took 0ms | statement | connection 19| url jdbc:oracle:thin:@localhost:1521:xe
select m1_0.member_email,m1_0.member_name,m1_0.member_description,m1_0.created_at,m1_0.modified_at,w1_0.leader_email from tbl_workspace w1_0 join tbl_member_workspace mw1_0 on w1_0.workspace_id=mw1_0.workspace_id join tbl_member m1_0 on m1_0.member_email=mw1_0.member_id where m1_0.member_del_flag=?
select m1_0.member_email,m1_0.member_name,m1_0.member_description,m1_0.created_at,m1_0.modified_at,w1_0.leader_email from tbl_workspace w1_0 join tbl_member_workspace mw1_0 on w1_0.workspace_id=mw1_0.workspace_id join tbl_member m1_0 on m1_0.member_email=mw1_0.member_id where m1_0.member_del_flag='0';
  • ๊ธฐ๋ณธ Hibernate Logging์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ?๋กœ ์ˆจ๊ธด๋‹ค.
  • P6Spy๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์ด ๋…ธ์ถœ๋œ ์ฑ„๋กœ SQL๋ฌธ์ด Logging๋œ๋‹ค.
  • ํ•œ ์ค„๋กœ ํ‘œํ˜„๋˜์–ด ๋ณด๊ธฐ์— ๋ถˆํŽธํ•œ๋ฐ, ๋‹คํ–‰์Šค๋Ÿฝ๊ฒŒ๋„ P6Spy๋Š” Query Formatting์„ ์ง€์›ํ•œ๋‹ค.

Query Formatting

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
public class P6SpyConfig implements MessageFormattingStrategy {
	@PostConstruct
	public void setLogMessageFormat() {
		P6SpyOptions.getActiveInstance().setLogMessageFormat(this.getClass().getName());
	}
	
	@Override
	public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
		return String.format("[%s] | %d ms | %s", category, elapsed, formatSql(category, sql));
	}
	
	private String formatSql(String category, String sql) {
		if (sql != null && !sql.trim().isEmpty() && Category.STATEMENT.getName().equals(category)) {
			String trimmedSQL = sql.trim().toLowerCase(Locale.ROOT);
			if (trimmedSQL.startsWith("create") || trimmedSQL.startsWith("alter") || trimmedSQL.startsWith("comment")) {
				return FormatStyle.DDL.getFormatter().format(sql);
			} else {
				return FormatStyle.BASIC.getFormatter().format(sql);
			}
		}
		return sql;
	}
}
  • @PostConstruct๋Š” @Configuration์— ์˜ํ•ด ์˜์กด์„ฑ ์ฃผ์ž…์ด ์™„๋ฃŒ๋œ ํ›„ ์‹คํ–‰ํ•  ๋ฉ”์„œ๋“œ์— ์„ ์–ธํ•œ๋‹ค.
  • P6Spy ์˜ต์…˜์—์„œ ํ™œ์„ฑํ™”๋œ Instance๋ฅผ ๊บผ๋‚ด์„œ Formatting์„ Overridingํ•˜๋Š” ์ฝ”๋“œ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2025-03-06T01:01:07.304+09:00ย ย INFO 23432 --- [nio-8080-exec-8] p6spyย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย : [statement] | 1 ms | 
	select
		m1_0.member_email,
		m1_0.member_name,
		m1_0.member_description,
		m1_0.created_at,
		m1_0.modified_at,
		w1_0.leader_email 
	from
		tbl_workspace w1_0 
	join
		tbl_member_workspace mw1_0 
			on w1_0.workspace_id=mw1_0.workspace_id 
	join
		tbl_member m1_0 
			on m1_0.member_email=mw1_0.member_id 
	where
		m1_0.member_del_flag='0'
  • DB ์กฐํšŒํ•˜๋Š” ํŠน์ • ๋ฉ”์„œ๋“œ์˜ SQL๋ฌธ์„ Loggingํ•ด ๋ณด๋ฉด ์œ„์™€ ๊ฐ™์ด ์ถœ๋ ฅ ๋œ๋‹ค.

ํšŒ๊ณ 

  • logback์€ resultSet์„ Table ํ˜•์‹์œผ๋กœ Logging ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๊ต‰์žฅํžˆ ํŽธํ–ˆ๋˜ ๊ธฐ์–ต์ด ์žˆ๋‹ค.
  • P6Spy์„ ์ด๋ฒˆ์— ๋„์ž…ํ•ด๋ณด๋‹ˆ SQL๋ฌธ์„ ํ™•์ธํ•˜๋Š” ๊ธฐ๋Šฅ ๋ฐ–์— ์—†์–ด์„œ Logback ๋ณด๋‹ค๋Š” ๋ถˆํŽธํ•œ๋ฐ, ๊ทธ๋ž˜๋„ ๊ธฐ๋Šฅ์ด ์ œํ•œ๋œ ๋งŒํผ ๊ฐ€๋ณ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์–ด์„œ Trade-off๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ์„ ํƒํ•ด์•ผ๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.
This post is licensed under CC BY 4.0 by the author.