2026/09/10

오늘의 이야기

 


 


🔑 Oracle MERGE 성능 개선 방안


오라클 튜닝



 



  • ON 조건 인덱스 최적화 – MERGE는 대상과 소스를 조인하므로 ON 조건 컬럼에 인덱스 필요

  • 변경된 값만 UPDATE – 불필요한 UPDATE 방지

  • USING 절 단순화 – 복잡한 JOIN, GROUP BY 최소화

  • 병렬 처리 힌트 – 대용량 배치 작업 시 효과적

  • 실행 계획 확인 – EXPLAIN PLAN으로 Full Scan 여부 점검

  • 파티셔닝 활용 – 병목 완화 및 Local Index 사용

  • MERGE 분리 전략 – UPDATE와 INSERT를 분리해 옵티마이저 활용 극대화

  • 최신 통계 유지 – DBMS_STATS로 실행 계획 정확성 확보


⚠️ 실무에서 자주 발생하는 문제



  • Snapshot too old 오류 – Undo 영역 과다 사용 → 사전 필터링으로 해결

  • 인덱스 무시 문제 – 조건을 인라인 뷰로 먼저 적용

  • 뷰 패턴 주의 – DISTINCT, GROUP BY 포함된 뷰는 업데이트 불가


📊 개선 방법 비교








































개선 방법 효과 적용 상황
ON 조건 인덱스 Full Scan 방지 모든 MERGE
변경된 값만 UPDATE Undo/Redo 감소 대량 UPDATE
USING 절 단순화 실행 계획 단순화 복잡한 소스 쿼리
병렬 처리 힌트 대용량 처리 속도 향상 배치 작업
MERGE 분리 전략 옵티마이저 활용 극대화 대규모 UPSERT
최신 통계 유지 실행 계획 정확성 확보 정기적 유지보수

📌 MERGE 실행 계획 튜닝 예제


1. 기본 MERGE 구문


MERGE INTO target t
USING source s
ON (t.id = s.id)
WHEN MATCHED THEN
UPDATE SET t.value = s.value
WHEN NOT MATCHED THEN
INSERT (id, value) VALUES (s.id, s.value);

2. 실행 계획 (인덱스 없는 경우)


| Id  | Operation          | Name   | Rows | Cost |
| 2 | TABLE ACCESS FULL | TARGET | 100K | 500 |
| 3 | TABLE ACCESS FULL | SOURCE | 100K | 400 |

3. 실행 계획 (인덱스 추가 후)


| Id  | Operation            | Name        | Rows | Cost |
| 2 | TABLE ACCESS BY INDEX ROWID | TARGET | 100K | 120 |
| 3 | INDEX RANGE SCAN | IDX_TARGET_ID | 100K | 80 |
| 4 | TABLE ACCESS BY INDEX ROWID | SOURCE | 100K | 100 |
| 5 | INDEX RANGE SCAN | IDX_SOURCE_ID | 100K | 70 |

📌 병렬 MERGE 예제


ALTER SESSION ENABLE PARALLEL DML;

MERGE /*+ parallel(t 4) parallel(s 4) */
INTO target t
USING source s
ON (t.id = s.id)
WHEN MATCHED THEN
UPDATE SET t.value = s.value
WHEN NOT MATCHED THEN
INSERT (id, value) VALUES (s.id, s.value);

병렬 실행 계획 특징


| Id  | Operation            | Name   |
| 1 | PX COORDINATOR | |
| 3 | PX SEND BROADCAST | |
| 5 | PX BLOCK ITERATOR | SOURCE |
| 9 | PX BLOCK ITERATOR | TARGET |

👉 PX 단계가 나타나면 병렬 처리 성공! 대용량 MERGE 성능이 크게 향상됩니다.





오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/09

오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/08

오늘의 이야기

Oracle OFFSET 성능 최적화와 Keyset 페이징


페이징



 


OFFSET은 데이터가 많아질수록 성능이 급격히 떨어집니다. 대용량 환경에서는 Keyset Pagination(Seek 방식)을 사용하고, 정렬 컬럼에 적절한 인덱스를 추가하는 것이 가장 효과적인 방법입니다.




OFFSET 성능 문제



  • OFFSET-FETCH 방식은 지정된 OFFSET만큼 데이터를 건너뛰기 위해 정렬 후 스캔을 수행합니다.

  • 데이터가 수백만 건 이상이면 TEMP 공간 사용과 CPU 부하가 급격히 증가합니다.




페이징 방식 비교





























방식 장점 단점 성능 특성
ROW_NUMBER 정렬 순서 보장, 임의 페이지 접근 가능 전체 정렬 비용 발생 대량 데이터에서 성능 저하
OFFSET-FETCH SQL 문법 간결, 직관적 OFFSET 커질수록 성능 급격히 저하 수백만 건 이상에서 비효율적
Keyset Pagination 불필요한 데이터 건너뛰지 않음, 일정한 성능 임의 페이지 접근 불가, 마지막 키 값 필요 대량 데이터에서도 안정적



Keyset 페이징 샘플 코드


1페이지 (처음 50개)


SELECT *
FROM orders
ORDER BY created_at, order_id
FETCH FIRST 50 ROWS ONLY;

2페이지 이후 (Seek 방식)


SELECT *
FROM orders
WHERE (created_at, order_id) > (:lastCreatedAt, :lastOrderId)
ORDER BY created_at, order_id
FETCH FIRST 50 ROWS ONLY;

100번째 페이지 접근


SELECT *
FROM orders
WHERE (created_at, order_id) > (:lastCreatedAt_99, :lastOrderId_99)
ORDER BY created_at, order_id
FETCH FIRST 50 ROWS ONLY;



운영 전략



  • 순차 탐색: Keyset 본연의 방식, 성능 최적

  • 중간 키 값 캐싱: 임의 페이지 접근 가능, 애플리케이션에서 관리 필요

  • ROW_NUMBER 혼합: 특정 페이지 점프 가능, 대량 데이터에서는 성능 저하




결론



  • 소규모 데이터(10만 건 이하) → OFFSET-FETCH도 실용적

  • 대규모 데이터(100만 건 이상) → 반드시 Keyset Pagination + 인덱스 최적화

  • 엑셀 다운로드, 로그 조회 등 대량 처리 → Keyset 방식이 안정성과 성능 모두 우수





오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/07

[LottoAI] 1241회차 추천 번호

LottoAI 추천 리포트 - 1241회차

지난 회차 결과 (1240회차)
실제 당첨 번호: (11, 13, 19, 20, 31, 44) (보너스 27)
지난 추천 최고 적중: 3개


이번 회차 추천 Top 5

순위 번호 신뢰도 특징
1 5, 11, 13, 31, 32, 38 98.0% odd/even=4/2, sum=130, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized
2 3, 11, 12, 15, 26, 35 70.2% odd/even=4/2, sum=102, sum-profile=historical-edge, low-high-balance, overlap-minimized, collective-coverage-maximized
3 7, 19, 26, 30, 31, 45 50.0% odd/even=4/2, sum=158, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized
4 1, 6, 15, 27, 38, 45 49.9% odd/even=4/2, sum=132, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized
5 12, 13, 19, 20, 27, 41 49.7% odd/even=4/2, sum=132, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized

본 결과는 통계 기반 참고자료이며 당첨을 보장하지 않습니다.

오늘의 이야기


#스하리1000명프로젝트,
แพ้เกาหลีเหรอ? แม้ว่าคุณจะพูดภาษาเกาหลีไม่ได้ แต่แอปนี้จะช่วยให้คุณเดินทางได้อย่างง่ายดาย
เพียงพูดภาษาของคุณ ระบบจะแปล ค้นหา และแสดงผลลัพธ์เป็นภาษาของคุณ
เหมาะสำหรับนักเดินทาง! รองรับมากกว่า 10 ภาษา รวมถึงภาษาอังกฤษ ญี่ปุ่น จีน เวียดนาม และอื่นๆ อีกมากมาย
ลองตอนนี้!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/06

오늘의 이야기

 



JavaScript input 길이 체크 방법


이미지



 


1. 기본적인 길이 체크


JavaScript에서 input의 길이를 확인할 때는 value.length 속성을 사용합니다.


<input type="text" id="username" />
<button onclick="checkLength()">확인</button>

<script>
function checkLength() {
const input = document.getElementById("username").value;
const length = input.length;

if (length < 5) {
alert("입력값은 최소 5글자 이상이어야 합니다.");
} else {
alert("입력값 길이: " + length);
}
}
</script>

2. 주요 방법



  • value.length : 문자열 길이를 직접 확인

  • maxlength 속성 : HTML에서 입력 가능한 최대 길이를 제한


<input type="text" maxlength="10">


  • 이벤트 리스너 활용 : input 이벤트로 실시간 길이 체크


const input = document.getElementById("username");
input.addEventListener("input", () => {
console.log("현재 길이:", input.value.length);
});

3. 활용 팁


보통은 maxlength로 기본 제한을 두고, 추가적인 검증은 value.length로 처리하는 방식이 가장 많이 쓰입니다.




 





오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/05

오늘의 이야기


#스하리1000명프로젝트,
Nawala sa Korea? Kahit na hindi ka nagsasalita ng Korean, tinutulungan ka ng app na ito na madaling makalibot.
Sabihin lang ang iyong wika—ito ay nagsasalin, naghahanap, at nagpapakita ng mga resulta pabalik sa iyong wika.
Mahusay para sa mga manlalakbay! Sinusuportahan ang 10+ wika kabilang ang English, Japanese, Chinese, Vietnamese, at higit pa.
Subukan ito ngayon!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/04

오늘의 이야기

 


 


DevExtreme dxDataGrid 활용 정리


이미지도 만들기



 


이번 글에서는 DevExtreme dxDataGrid를 사용하면서 자주 쓰이는 기능과 팁들을 정리했습니다. JavaScript와 함께 동적으로 데이터를 제어하거나 UI를 커스터마이징할 때 유용합니다.


1. 특정 셀 숨기기



cellTemplate을 활용하여 조건에 따라 셀을 숨길 수 있습니다.




columns: [
{
dataField: "Phone",
cellTemplate: function(container, options) {
if (options.data.IsHidden) {
container.text(""); // 숨김 처리
} else {
container.text(options.value);
}
}
}
]

2. 특정 컬럼 숨기기/보이기



var grid = $("#gridContainer").dxDataGrid("instance");

// 컬럼 숨기기
grid.columnOption("Phone", "visible", false);

// 다시 보이기
grid.columnOption("Phone", "visible", true);

3. 조건에 맞는 항목 값 추출


JavaScript에서 filtermap을 조합하면 조건에 맞는 데이터를 쉽게 뽑을 수 있습니다.



const namesWithY = dataSource
.filter(item => item.status === "Y")
.map(item => item.name);

4. 조건에 맞는 항목의 Key 추출



const yKeys = Object.keys(row).filter(key => row[key] === "Y");

5. 전체 그리드에서 Y 값이 있는 컬럼 찾기



const yKeysAll = dataSource
.map(row => Object.keys(row).filter(key => row[key] === "Y"))
.flat();

const uniqueYKeys = [...new Set(yKeysAll)];

6. 조건에 맞는 컬럼만 보이게 설정



const grid = $("#gridContainer").dxDataGrid("instance");

// 모든 컬럼 숨기기
grid.getVisibleColumns().forEach(col => {
grid.columnOption(col.dataField, "visible", false);
});

// Y가 나온 컬럼만 보이게
uniqueYKeys.forEach(key => {
grid.columnOption(key, "visible", true);
});

7. 문자열 첫 글자만 추출



const str = "Hello";
console.log(str.charAt(0)); // "H"
console.log(str[0]); // "H"
console.log(str.slice(0,1)); // "H"

8. dxDataGrid에서 배경색 변경


columnOption으로는 스타일 변경이 불가능합니다. 대신 onCellPrepared 또는 onRowPrepared 이벤트를 사용해야 합니다.



onCellPrepared: function(e) {
if (e.rowType === "data" && e.column.dataField === "status") {
if (e.value === "Y") {
e.cellElement.css("background-color", "#d1ffd1");
}
}
}


onRowPrepared: function(e) {
if (e.rowType === "data" && e.data.status === "Y") {
e.rowElement.css("background-color", "#e0f7fa");
}
}

마무리


dxDataGrid는 데이터 표시와 관리에 강력한 기능을 제공하지만, 세부적인 스타일링이나 조건부 제어는 이벤트 기반 접근이 필요합니다. 위의 예시들을 활용하면 다양한 상황에서 유연하게 대응할 수 있습니다.





오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/03

오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/02

오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/09/01

오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/08/31

오늘의 이야기

설치 예시




라즈베리 파이에 Docker 설치 및 서비스 구동 가이드


라즈베리 파이(Raspberry Pi)를 홈 서버로 활용할 때 가장 유용한 도구 중 하나가 바로 Docker입니다. 복잡한 환경 설정 없이 컨테이너 형태로 다양한 서비스를 쉽게 띄울 수 있기 때문입니다.


이번 글에서는 라즈베리 파이에 Docker를 설치하는 전체 과정부터, 특정 서비스를 백그라운드에서 구동하는 방법, 그리고 흔히 마주치는 컨테이너 이름 충돌(Conflict) 오류를 해결하는 방법까지 정리해 보았습니다.


1. 라즈베리 파이에 Docker 설치하기


라즈베리 파이 OS에서 가장 쉽고 확실하게 Docker를 설치하는 방법은 공식 자동 설치 스크립트를 사용하는 것입니다.


① 시스템 업데이트


설치를 시작하기 전, 시스템 패키지들을 최신 상태로 업데이트합니다.


sudo apt-get update
sudo apt-get upgrade -y

② Docker 설치 스크립트 실행


아래 명령어를 통해 공식 스크립트를 다운로드하고 실행합니다. 라즈베리 파이의 아키텍처(ARM)에 맞는 버전을 알아서 찾아 설치해 줍니다.


curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

③ 사용자 권한 설정 (핵심!)


기본적으로 Docker 명령어는 root 권한이 필요하여 매번 sudo를 입력해야 합니다. 이를 방지하기 위해 현재 사용자를 docker 그룹에 추가합니다.


sudo usermod -aG docker $USER

💡 참고: 권한을 적용하려면 라즈베리 파이를 재부팅하거나 newgrp docker 명령어를 입력하세요. SSH 접속이라면 연결을 끊었다가 다시 접속하면 됩니다.

④ 설치 확인


정상적으로 설치되었는지 버전과 테스트 컨테이너로 확인합니다.


docker --version
docker run hello-world

2. 백그라운드에서 Docker 컨테이너 실행하기


Docker 설치가 완료되었다면 원하는 서비스를 컨테이너로 실행할 수 있습니다. 이번 예시에서는 diegosouzapw/omniroute:latest 이미지를 기반으로 서비스를 구동해보겠습니다.


docker run -d --name omniroute -p 20128:20128 diegosouzapw/omniroute:latest


  • -d: 백그라운드에서 실행(Detached mode)하여 터미널을 꺼도 서비스가 유지되게 합니다.

  • --name omniroute: 구별하기 쉽도록 컨테이너의 이름을 'omniroute'로 지정합니다.

  • -p 20128:20128: 접속을 위해 라즈베리 파이의 20128 포트를 컨테이너의 20128 포트와 연결합니다.


명령어 실행 후 긴 영문/숫자 조합(컨테이너 ID)이 출력되면 성공입니다. docker ps 명령어를 입력해 STATUS가 Up인지 확인하고, 동일한 네트워크(Wi-Fi 등)에 있는 PC나 스마트폰 브라우저에서 http://[라즈베리파이_IP주소]:20128로 접속하면 웹 대시보드 화면을 볼 수 있습니다.


3. 흔한 오류 해결: "The container name is already in use"


컨테이너를 실행하다 보면 아래와 같은 오류 메시지를 만날 때가 있습니다.


docker: Error response from daemon: Conflict. The container name "/omniroute" is already in use by container "...". You have to remove (or rename) that container to be able to reuse that name.

이것은 지정한 이름(이 경우 'omniroute')을 가진 컨테이너가 이미 만들어져 존재하기 때문에 발생하는 이름 충돌(Conflict) 오류입니다. 컨테이너가 종료된 상태로 남아있거나 이전에 동일한 명령어를 이미 실행했을 경우 발생합니다. 상황에 따라 아래의 두 가지 방법으로 해결할 수 있습니다.


방법 A: 기존 컨테이너를 완전히 삭제하고 새로 실행 (추천)


가장 깔끔하게 처음부터 설정을 적용하여 다시 띄우고 싶을 때 사용하는 방법입니다.


# 1. 기존 컨테이너 강제 삭제
docker rm -f omniroute

# 2. 기존 명령어 다시 실행
docker run -d --name omniroute -p 20128:20128 diegosouzapw/omniroute:latest

방법 B: 기존에 생성된 컨테이너를 다시 시작하기


새로 컨테이너를 지우고 만들 필요 없이, 단순히 멈춰 있는 기존 컨테이너를 켜기만 할 때 사용합니다.


docker start omniroute

위 방법 중 하나를 적용한 후 다시 터미널에 docker ps를 쳐서 목록에 컨테이너가 잘 나타난다면 완벽하게 해결된 것입니다!





[LottoAI] 1240회차 추천 번호

LottoAI 추천 리포트 - 1240회차

지난 회차 결과 (1239회차)
실제 당첨 번호: (11, 13, 22, 32, 33, 36) (보너스 8)
지난 추천 최고 적중: 2개


이번 회차 추천 Top 5

순위 번호 신뢰도 특징
1 13, 15, 18, 32, 33, 38 98.0% odd/even=3/3, sum=149, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized
2 7, 12, 15, 22, 35, 38 50.0% odd/even=3/3, sum=129, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized
3 6, 7, 11, 19, 32, 38 50.0% odd/even=3/3, sum=113, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized
4 11, 13, 22, 34, 38, 42 50.0% odd/even=2/4, sum=160, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized
5 10, 18, 19, 22, 31, 38 50.0% odd/even=2/4, sum=138, sum-profile=historical-center, low-high-balance, overlap-minimized, collective-coverage-maximized

본 결과는 통계 기반 참고자료이며 당첨을 보장하지 않습니다.

오늘의 이야기


#스하리1000명프로젝트,
¿Perdido en Corea? Incluso si no hablas coreano, esta aplicación te ayuda a moverte fácilmente.
Simplemente hable su idioma: traduce, busca y muestra resultados en su idioma.
¡Genial para viajeros! Admite más de 10 idiomas, incluidos inglés, japonés, chino, vietnamita y más.
¡Pruébalo ahora!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/08/30

오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/08/29

오늘의 이야기


#스하리1000명프로젝트,

Lost in Korea? Even if you don't speak Korean, this app helps you get around easily.
Just speak your language—it translates, searches, and shows results back in your language.
Great for travelers! Supports 10+ languages including English, Japanese, Chinese, Vietnamese, and more.
Try it now!

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




오늘의 이야기

    🔑 Oracle MERGE 성능 개선 방안 오라클 튜닝   ON 조건 인덱스 최적화 – MERGE는 대상과 소스를 조인하므로 ON 조건 컬럼에 인덱스 필요 변경된 값만 U...