# 장헌 7개 서비스 PHP·SQL 프로파일링 세미나 대상: A팀 기술회의 측정일: 2026-07-31 환경: 정상 환경과 분리한 `jang-profile`, PHP 8.4.23, Xdebug 3.5.3, MySQL 8.4 Performance Schema ## 1. 오늘 확인할 질문 1. 화면이 열린다는 사실과 기능이 정상이라는 사실을 어떻게 구분하는가? 2. 평균 응답시간 뒤에 숨은 느린 PHP 함수와 SQL을 측정하는가? 3. 권한차단·외부의존·데이터부재를 실제 실패와 구분하는가? 4. 쓰기 테스트 후 DB와 합성 데이터가 원상태인지 확인하는가? 5. 양 팀이 배포 전후 동일한 측정 기준을 사용할 수 있는가? 발표 메모: > 이번 결과는 단순 화면 캡처가 아닙니다. 계정, 서비스, 메뉴, 기능, > DB 변화, PHP 함수와 SQL을 서로 연결해 본 결과입니다. ## 2. 측정 환경과 안전장치 - 정상 환경: `jang-p12-auto-r10`, `127.0.0.1:18091` - 프로파일 환경: `jang-profile`, `127.0.0.1:18092` - 별도 웹·DB·세션·첨부파일·로그·프로파일 볼륨 사용 - 원본 DB를 읽기 전용 덤프로 복제 - 원본과 복제본 모두 DB 객체 462개, 뷰 13개 - 평상시 Xdebug 비활성, 지정 트리거 요청만 프로파일링 - 정상 환경과 프로파일 환경 모두 최종 `healthy` 발표 메모: > 운영과 비슷한 데이터를 사용하되 테스트 쓰기는 복제 DB에만 > 발생하도록 분리했습니다. 프로파일러는 모든 요청에 켜지 않았습니다. ## 3. 계정·서비스·메뉴·기능 범위 | 측정 축 | 실행 수 | 결과 | | --- | ---: | --- | | 7계정 × 7서비스 대표 접근 | 49 | 정상 46, 권한차단 3 | | 승인 역할 × 실제 메뉴 조회 | 135 | 정상 128, 의존 6, 데이터부재 1 | | 서비스별 쓰기·권한·DB정리 | 7시나리오×2회 | 14/14 통과 | | 전체 통합 매트릭스 | 191행 | 실패 0 | 주의: - 7계정으로 135개 메뉴를 각각 실행한 945건 완전 교차 검사는 아니다. - 49개 대표 접근으로 계정의 서비스 진입을 확인했다. - 135개 메뉴는 서비스별 승인 역할로 확인했다. - 메뉴별 타 역할 권한은 추가 확인 범위다. 발표 메모: > 숫자를 부풀리지 않기 위해 대표 접근과 메뉴 탐색을 분리했습니다. > 현재 확정 가능한 범위와 아직 측정하지 않은 범위를 같은 표에 둡니다. ## 4. 결과 분류 | 분류 | 건수 | 의미 | | --- | ---: | --- | | 정상 | 181 | 기대한 인증·조회·쓰기 경계·정리 통과 | | 권한차단 | 3 | 비인사 역할의 인사관리 로그인 거부 | | 외부 라이브러리 의존 | 3 | jspreadsheet, Google Maps, Summernote | | 부모 실행문맥 의존 | 3 | 부모 프레임·선행 화면 없이 단독 실행 불가 | | 데이터부재 | 1 | 선행 선택 전 빈 출하 목록 | | 실패 | 0 | HTTP·기능 실패 없음 | 발표 메모: > 권한이 막힌 것을 실패라고 세지 않았고, 데이터가 없는 화면도 > 프로그램 오류와 분리했습니다. 부모 프레임이 필요한 화면 역시 > 외부 장애와 구분했습니다. ## 5. 기능별 DB 변경 전후 - 인트라넷 일정 합성 등록·권한차단·삭제: 잔여 0 - 공장 공통코드 합성 등록·수정·삭제: 잔여 0 - 인사 탄력근무 합성 등록·수정·삭제: 잔여 0 - 사업 기초코드 합성 등록·수정·삭제: 잔여 0 - 회계 계정코드 합성 등록·수정·삭제: 잔여 0 - 가상야적장 익명 쓰기 차단: 핵심 DB 행 수 불변 - 터치스크린 쓰기·배치 7개 진입점 차단: DB 스냅샷 불변 발표 메모: > 쓰기 성공만 확인한 것이 아니라 테스트 종료 후 잔여와 핵심 테이블 > 불변까지 확인했습니다. 운영 데이터를 흉내 낸 값은 남기지 않았습니다. ## 6. 서비스별 대표 응답시간 워밍업 2회 후 일반 요청 5회의 로컬 단일 요청 결과: | 서비스 | p50 | p95 | 최대 | | --- | ---: | ---: | ---: | | intranet | 4.627ms | 5.882ms | 5.882ms | | factory_mng | 11.087ms | 11.850ms | 11.850ms | | person_mng | 3.202ms | 3.789ms | 3.789ms | | projt_mng | 13.893ms | 14.488ms | 14.488ms | | account | 4.830ms | 5.262ms | 5.262ms | | virtual_yard | 16.632ms | 18.006ms | 18.006ms | | factory_board | 11.730ms | 12.777ms | 12.777ms | 해석: - 현재 대표 화면에서 절대 응답시간은 짧다. - 브라우저 전체 렌더링, 외부 자원, 대량 동시성 결과와 동일하지 않다. - 표본이 작으므로 운영 SLA나 용량 결론으로 사용하지 않는다. ## 7. Xdebug 측정 방식과 오버헤드 - 서비스별 일반 요청 5회 - 서비스별 Xdebug 요청 3회 - 고유 Cachegrind 21개 - 파일명에 마이크로초 `%u`를 사용해 덮어쓰기 방지 | 서비스 | 일반 p50 | 프로파일 중앙값 | 관측 배수 | | --- | ---: | ---: | ---: | | intranet | 4.627ms | 5.108ms | 1.104x | | factory_mng | 11.087ms | 11.320ms | 1.021x | | person_mng | 3.202ms | 3.505ms | 1.095x | | projt_mng | 13.893ms | 14.766ms | 1.063x | | account | 4.830ms | 4.997ms | 1.035x | | virtual_yard | 16.632ms | 16.547ms | 0.995x | | factory_board | 11.730ms | 11.675ms | 0.995x | 발표 메모: > 1배 미만은 프로파일러가 성능을 높였다는 뜻이 아니라 작은 표본의 > 변동입니다. Cachegrind의 함수 순위에는 사용할 수 있지만 운영 > 오버헤드 결론에는 더 많은 반복이 필요합니다. ## 8. 느린 PHP 함수 Top 서비스별 프로파일 3회 합계 self time: | 순위 | 서비스 | 함수 | self time | | ---: | --- | --- | ---: | | 1 | virtual_yard | `mysqli_real_connect` | 22.412ms | | 2 | projt_mng | `mysqli_query` | 13.118ms | | 3 | factory_mng | `mysqli_query` | 9.878ms | | 4 | projt_mng | `mysqli_real_connect` | 7.223ms | | 5 | factory_mng | `mysqli_real_connect` | 6.309ms | | 6 | virtual_yard | `mysqli_set_charset` | 4.391ms | | 7 | account | `mysqli_real_connect` | 2.753ms | | 8 | projt_mng | Smarty compiled process | 2.103ms | 해석: - 대표 요청에서는 DB 연결·쿼리 비용이 우선 관찰 대상이다. - 그다음은 Smarty 컴파일 결과 처리와 렌더링이다. - 지속 연결 적용 여부는 효과뿐 아니라 세션·장애 복구를 함께 검증해야 한다. ## 9. 느린 SQL Top Performance Schema digest 초기화 후 7개 대표 화면을 5회 반복: | 순위 | 유형 | 호출 | 총시간 | 평균 | 최대 | 검사행 | | ---: | --- | ---: | ---: | ---: | ---: | ---: | | 1 | 근태 집계 | 155 | 45.939ms | 0.296ms | 0.422ms | 18,755 | | 2 | 출퇴근 조회 | 155 | 22.894ms | 0.148ms | 0.227ms | 0 | | 3 | 팝업 공지 조회 | 5 | 17.613ms | 3.523ms | 3.924ms | 12,925 | | 4 | 가상야적장 상태 조회 | 5 | 13.174ms | 2.635ms | 2.898ms | 9,980 | | 5 | 시스템 설정 조회 | 15 | 11.158ms | 0.744ms | 0.904ms | 10,185 | 관찰: - 팝업 공지와 가상야적장 상태 조회는 각 5회 모두 no-index가 기록됐다. - 근태 집계는 절대시간은 짧지만 호출 155회와 no-index 155회다. - 즉시 인덱스를 추가하지 않고 `EXPLAIN`과 데이터 증가 조건을 확인한다. ## 10. 발견 후 보정한 PHP 경고 - 관리자 계정의 사업관리 홈에서만 재현 - 비활성 화면이 HTML 주석 안에 있었지만 Smarty는 내부 변수를 컴파일 - `Undefined array key` 18건 - 연쇄 null 속성 접근 18건 - 합계 36건, HTTP 응답은 200 보정: - 공통 홈 렌더링 전에 비활성 화면 변수의 빈 기본값을 지정 - 문서 조회 함수에도 조회 결과 0건 기본값을 지정 - 사업관리 7계정 재검사: 7/7 HTTP 200, PHP Warning 0 - 7개 서비스 대표 회귀: 7/7 HTTP 200, PHP 오류 0 판정: 즉시 수정 완료, 프로파일 환경 검증 완료 ## 11. 조치 분류 ### 즉시 수정 - 현재 확인된 HTTP·기능 실패는 0건 - 사업관리 관리자 조건 Warning 36건 보정 및 회귀 완료 ### 추가 확인 - 공지·가상야적장 SQL 실행계획과 복합 인덱스 후보 - 근태 쿼리 155회 호출의 중복 제거 가능성 - jspreadsheet·Google Maps·Summernote 로딩 정책 - 부모 프레임 의존 화면의 실제 메뉴 진입 검사 - 데이터부재 화면의 합성 기준 데이터 - 메뉴별 타 역할 권한 완전 교차가 필요한 범위 ### 현행 유지 - 46개 정상 계정·서비스 대표 접근 - 128개 정상 메뉴 조회 - 14회 쓰기·권한·정리 결과 - 정상 환경에서 Xdebug 비활성 정책 ## 12. A팀에 묻는 비교 질문 1. 서비스별 p50·p95·p99와 최대를 측정하는가? 2. 워밍업, 데이터 조건, 반복 횟수, 동시성을 고정하는가? 3. PHP 함수별 self·inclusive time과 호출 횟수를 보는가? 4. SQL digest별 총·평균·최대시간과 rows examined를 보는가? 5. no-index와 임시 디스크 테이블을 배포 전후 비교하는가? 6. OPcache hit/miss와 메모리 고갈을 감시하는가? 7. 계정×서비스×메뉴×기능 권한표가 있는가? 8. 쓰기 테스트 전후 DB 변화와 합성 잔여 0을 확인하는가? 9. 권한차단·외부의존·데이터부재를 실패와 구분하는가? 10. 프로파일 산출물의 크기 제한·보관·폐기 기준이 있는가? 11. 운영에서 프로파일러를 활성화할 때 승인과 종료 조건이 있는가? 12. 양 팀이 같은 시나리오로 배포 전후 회귀 비교할 수 있는가? ## 13. 회의에서 합의할 제안 - 공통 결과 분류 코드와 증적 형식 - 대표 시나리오·테스트 계정·합성 데이터 규칙 - p50·p95·p99·최대와 SQL digest 기본 항목 - PHP·SQL Top N 산출 기준 - 프로파일러 운영 활성화 금지 또는 승인 절차 - 합성 데이터 접두어와 종료 후 잔여 0 원칙 - 배포 전후 동일 시나리오 비교와 결과 보관 기간 ## 14. 결론 - 7개 서비스는 현재 대표 접근·조회·쓰기 경계에서 실제 실패 0건이다. - 권한차단·의존·데이터부재를 실패와 분리했다. - DB 변경 후 합성 잔여 0 또는 스냅샷 불변을 확인했다. - PHP 병목 후보는 DB 연결·쿼리와 Smarty 렌더링이다. - SQL 확장 위험 후보는 팝업 공지, 가상야적장, 반복 근태 집계다. - 다음 기술 작업은 SQL `EXPLAIN` 비교와 의존 화면 실제 진입 검증이다. 발표 마무리: > A팀이 이미 같은 항목을 측정하고 있다면 도구 이름보다 결과 형식을 > 맞추는 것이 중요합니다. 측정하지 않는 항목이 있다면 이번 장헌 > 매트릭스와 프로파일 결과를 공통 출발점으로 제안합니다. ## 증적 위치 - 통합 매트릭스: `docs/evidence/p12/uat/2026-07-31_account-service-menu-function-matrix.csv` - 응답시간: `data/test-artifacts/profile-20260731-unique/seven-service-profile/` - PHP 함수: `data/test-artifacts/profile-20260731-unique/cachegrind-analysis/` - SQL digest: `data/test-artifacts/profile-20260731-unique/sql-analysis/digest-top.tsv` - 진행 관리: `new-pc-development-setup-stabilization.md`