[Developer] #567 list latest SQL cursors without time cutoff

This commit is contained in:
devmrko
2026-07-01 15:14:27 +09:00
parent b39968d43f
commit 57d77d2df2
3 changed files with 5 additions and 6 deletions

View File

@@ -138,7 +138,7 @@
## 13. SQL_ID 실행 증적 확장 — 2026-07-01 ## 13. SQL_ID 실행 증적 확장 — 2026-07-01
재현 SQL만으로는 “이 조건이 실제 DB cursor에 적용됐는가”를 충분히 설명하지 못한다. `/probe` 성공·0행 결과 뒤에 백오피스는 `V$SQL`에서 최근 15분의 최신 cursor 10건을 먼저 읽고, Java에서 `SQL_FULLTEXT`에 보호 객체명이 있는 cursor만 고른다. DB에서 SQL 텍스트를 `LIKE`로 필터링하지 않아 ORDS Handler의 PL/SQL·공백·긴 SQL 표현 때문에 놓치는 문제를 줄인다. 이어 `DBMS_XPLAN.DISPLAY_CURSOR(SQL_ID, CHILD_NUMBER, 'ALLSTATS LAST +PREDICATE +ALIAS')`의 Predicate Information을 함께 표시한다. 재현 SQL만으로는 “이 조건이 실제 DB cursor에 적용됐는가”를 충분히 설명하지 못한다. `/probe` 성공·0행 결과 뒤에 백오피스는 `V$SQL`에서 시간 조건 없이 마지막 활성 cursor 10건을 먼저 읽고, Java에서 `SQL_FULLTEXT`에 보호 객체명이 있는 cursor만 고른다. DB에서 SQL 텍스트를 `LIKE`로 필터링하지 않아 ORDS Handler의 PL/SQL·공백·긴 SQL 표현 때문에 놓치는 문제를 줄인다. 이어 `DBMS_XPLAN.DISPLAY_CURSOR(SQL_ID, CHILD_NUMBER, 'ALLSTATS LAST +PREDICATE +ALIAS')`의 Predicate Information을 함께 표시한다.
| 화면 증적 | DB 출처 | 의미 | | 화면 증적 | DB 출처 | 의미 |
|---|---|---| |---|---|---|

View File

@@ -46,7 +46,6 @@ public class OrdsProbeService {
private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<>() { private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<>() {
}; };
private static final Logger log = LoggerFactory.getLogger(OrdsProbeService.class); private static final Logger log = LoggerFactory.getLogger(OrdsProbeService.class);
private static final int EXECUTION_EVIDENCE_LOOKBACK_MINUTES = 15;
private record ExecutionEvidenceLookup( private record ExecutionEvidenceLookup(
SqlExecutionEvidence evidence, SqlExecutionEvidence evidence,
@@ -277,7 +276,7 @@ public class OrdsProbeService {
lookup.candidates()); lookup.candidates());
} }
return result.withExecutionEvidence(null, return result.withExecutionEvidence(null,
"근 15분의 최신 실행 cursor 10건에서 이 보호 대상을 찾지 못했습니다. " "최신 실행 cursor 10건에서 이 보호 대상을 찾지 못했습니다. "
+ "아래 원문 SQL을 직접 확인하세요.", + "아래 원문 SQL을 직접 확인하세요.",
lookup.candidates()); lookup.candidates());
} }
@@ -339,7 +338,7 @@ public class OrdsProbeService {
elapsed_time, elapsed_time,
buffer_gets buffer_gets
FROM v$sql FROM v$sql
WHERE last_active_time >= SYSTIMESTAMP - NUMTODSINTERVAL(?, 'MINUTE') WHERE last_active_time IS NOT NULL
ORDER BY last_active_time DESC ORDER BY last_active_time DESC
) )
WHERE ROWNUM <= 10 WHERE ROWNUM <= 10
@@ -354,7 +353,7 @@ public class OrdsProbeService {
resultSet.getLong("rows_processed"), resultSet.getLong("rows_processed"),
Math.round(resultSet.getLong("elapsed_time") / 1000.0d), Math.round(resultSet.getLong("elapsed_time") / 1000.0d),
resultSet.getLong("buffer_gets") resultSet.getLong("buffer_gets")
), EXECUTION_EVIDENCE_LOOKBACK_MINUTES); ));
List<SqlExecutionCandidate> candidateViews = candidates.stream() List<SqlExecutionCandidate> candidateViews = candidates.stream()
.map(candidate -> new SqlExecutionCandidate( .map(candidate -> new SqlExecutionCandidate(

View File

@@ -112,7 +112,7 @@
<div class="section-heading compact-heading"> <div class="section-heading compact-heading">
<div> <div>
<h3>DB 실행 증적</h3> <h3>DB 실행 증적</h3>
<p class="section-subtitle">최근 15분의 최신 DB cursor 10건에서 같은 보호 대상을 찾아 SQL_ID로 확인한 결과입니다.</p> <p class="section-subtitle">DB가 보관한 최신 cursor 10건에서 같은 보호 대상을 찾아 SQL_ID로 확인한 결과입니다.</p>
</div> </div>
<span class="badge text-bg-success" th:text="${'SQL_ID ' + result.executionEvidence().sqlId()}">SQL_ID</span> <span class="badge text-bg-success" th:text="${'SQL_ID ' + result.executionEvidence().sqlId()}">SQL_ID</span>
</div> </div>