같은 종류의 확인 요청이 일주일에 몇 번씩 왔다. 어제 수집 안 된 장치 목록을 뽑아 달라는 것이었다.
올 때마다 SELECT 를 새로 짰는데 대충 기억하고 있으니 몇 분이면 되는 일로 봤다.
Table of contents
Open Table of contents
매번 조금씩 달랐다
같은 요청인데 짤 때마다 조금씩 달랐다.
-- 1차
SELECT device_id FROM device WHERE device_id NOT IN
(SELECT DISTINCT device_id FROM device_data WHERE DATE(reg_date)='2017-02-18');
-- 2차
SELECT d.device_id FROM device d
LEFT JOIN device_data dd ON dd.device_id=d.device_id AND DATE(dd.reg_date)='2017-02-18'
WHERE dd.device_id IS NULL;
NOT IN 으로 짠 것과 LEFT JOIN 으로 짠 것인데 결과가 한 번 달랐다. 첫 번째가 비활성 장치까지 포함하고 있었다.
받는 쪽에서 보면 같은 질문에 다른 답이 온 것이다. 자료가 바뀐 것이 아니라 내가 짠 WHERE 가 달랐다.
매번 짜면 매번 다르고 기억에 의존하는 한 이 어긋남은 계속 생긴다.
조치 — 스크립트로 옮기기
한 번 제대로 짜고 그것만 쓰기로 했다.
#!/bin/sh
# 지정한 날짜에 자료를 안 보낸 장치 목록
# 사용법: no-data.sh [YYYY-MM-DD] (기본: 어제)
D=${1:-$(date -d yesterday +%Y-%m-%d)}
mysql -h db -N -e "
SELECT d.device_id, d.name, d.location
FROM device d
LEFT JOIN (
SELECT DISTINCT device_id FROM device_data
WHERE reg_date >= '${D} 00:00:00' AND reg_date < '${D} 23:59:59'
) dd ON dd.device_id = d.device_id
WHERE d.use_yn = 'Y' AND dd.device_id IS NULL
ORDER BY d.device_id;
"
날짜를 인자로 받고 안 주면 date -d yesterday 로 어제를 쓰므로 다음부터는 실행만 하면 된다.
use_yn = 'Y' 조건이 핵심이었다. 이것을 넣었다 뺐다 해서 결과가 갈렸던 것이다.
검증 — 전체 개수 함께 내기
mysql -N 로 목록만 내면 0건일 때 판단이 안 선다.
TOTAL=$(mysql -h db -N -e "SELECT COUNT(*) FROM device WHERE use_yn='Y'")
echo "활성 장치 ${TOTAL}대 기준, ${D} 미수집 목록"
echo "---"
# ... 조회 ...
echo "---"
echo "미수집 ${CNT}대"
COUNT(*) 로 활성 장치 수를 먼저 세어 머리말에 찍는다.
활성 장치 42대 기준, 2017-02-18 미수집 목록
---
D012 3공장 A라인 ...
D019 3공장 B라인 ...
---
미수집 2대
TOTAL 이 42로 나오면 0건은 전부 수집됐다는 뜻이고 TOTAL 이 0이면 조회 쪽이 잘못된 것이다.
숫자가 없으면 이 둘이 같은 화면으로 보인다. 아무것도 안 잰 것과 재서 0인 것을 이 한 줄이 가른다.
자주 쓰는 것을 모았다
이런 스크립트가 늘어서 한 폴더에 모았다.
tools/
no-data.sh 미수집 장치
slow-query.sh 느린 쿼리
disk-usage.sh 서버별 디스크
error-summary.sh 오류 집계
README.md
README.md 에 각각이 무엇을 하는지 적었다.
## no-data.sh
지정한 날짜에 자료를 안 보낸 활성 장치 목록.
./no-data.sh 어제
./no-data.sh 2017-02-15 특정 날짜
주의: use_yn='Y' 인 장치만 대상. 비활성 장치는 안 나옴.
주의 항목이 특히 중요했는데 무엇이 대상에서 빠지는지를 안 적으면 다음 사람이 결과를 오해한다.
숫자만 받아 든 사람은 그 숫자가 무엇을 안 셌는지 모르므로 도구를 넘길 때 그것도 같이 넘겨야 했다.
정기 실행으로 바꿨다
요청이 계속 오니 아예 매일 돌려 보내게 했다.
0 9 * * * /opt/tools/no-data.sh | mail -s "[일일] 미수집 장치" ops@example.com
cron 에 걸어 두니 물어보기 전에 먼저 가고 요청하고 기다리는 시간이 사라졌다.
결과가 0대여도 보내게 했는데 안 오면 스크립트가 죽은 것인지 0대인 것인지 알 수 없다.
조치 — 화면과 스크립트가 한 조회를 쓰게
메일보다 화면이 낫다는 얘기가 나와 관리자 화면에도 넣었는데 화면을 따로 짜면 숫자가 또 갈린다.
// models/Report_model.php
public function no_data_devices($date) { ... }
no_data_devices 하나를 두고 화면이 그것을 부르게 했다. 스크립트도 같은 것을 부르게 바꿨다.
php /opt/app/index.php report no_data "$D"
조회가 한 곳에 있으면 결과가 갈릴 자리가 없고 조건을 고칠 때도 한 번만 고치면 화면과 메일이 함께 바뀐다.
정리
- 반복되는 조회를 매번 짜면 매번 조금씩 다르다
use_yn같은 조건 하나로 결과가 갈린다- 한 번 제대로 짜고 날짜만 인자로 받는 스크립트로 옮긴다
- 목록만 내지 말고
COUNT(*)로 전체 개수를 함께 낸다 - 전체 수가 있어야 0건이 성공인지 조회 실패인지 갈린다
- 스크립트를 한 폴더에 모으고
README에 주의를 적는다 - 무엇이 대상에서 빠지는지를 적어야 결과를 오해하지 않는다
- 요청이 계속 오면
cron으로 돌리고 0건이어도 보낸다 - 화면과 스크립트가 같은 조회 하나를 부르게 한다