[Developer] #567 list latest SQL cursors without time cutoff
This commit is contained in:
@@ -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 출처 | 의미 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user