데이터베이스 문제
데이터베이스 관련 문제와 해결 방법입니다.
연결 문제
SQLSTATE[HY000] Connection refused
증상:
SQLSTATE[HY000] [2002] Connection refused
원인:
- PostgreSQL 컨테이너가 시작되지 않음
- 잘못된 호스트/포트 설정
- 네트워크 연결 문제
해결 방법:
-
컨테이너 상태 확인
make status NAME=myapp -
PostgreSQL 컨테이너 로그 확인
docker logs myapp-postgres -
.env 설정 확인
# .env
DB_CONNECTION=pgsql
DB_HOST=postgres # 컨테이너 이름 사용
DB_PORT=5432 # 컨테이너 내부 포트
DB_DATABASE=app
DB_USERNAME=app
DB_PASSWORD=secret -
네트워크 확인
docker network ls
docker network inspect myapp-network
SQLSTATE[08006] Unable to connect
증상:
SQLSTATE[08006] [7] could not connect to server: Connection timed out
원인:
- 외부 포트로 접속 시도
- 방화벽 문제
해결 방법:
컨테이너 간 통신은 내부 네트워크 사용:
# 올바른 설정 (컨테이너 간 통신)
DB_HOST=postgres
DB_PORT=5432
# 잘못된 설정 (외부 접속 시도)
DB_HOST=localhost
DB_PORT=5432
마이그레이션 문제
Duplicate column/table
증상:
SQLSTATE[42701]: Duplicate column: column "xxx" of relation "yyy" already exists
원인:
- 마이그레이션 파일 중복 실행
- 마이그레이션 상태 불일치
해결 방법:
-
마이그레이션 상태 확인
docker exec -it myapp-web php artisan migrate:status -
특정 마이그레이션 롤백
docker exec -it myapp-web php artisan migrate:rollback --step=1 -
마이그레이션 테이블 확인
SELECT * FROM migrations ORDER BY batch DESC;
주의
migrate:fresh는 모든 데이터를 삭제합니다. 운영 환경에서 절대 사용하지 마세요.
Nothing to migrate
증상:
Nothing to migrate.
원인:
- 모든 마이그레이션이 이미 실행됨
- 마이그레이션 파일이 없음
해결 방법:
-
마이그레이션 상태 확인
php artisan migrate:status -
새 마이그레이션 파일 확인
ls -la database/migrations/
RLS (Row-Level Security) 문제
데이터가 보이지 않음
증상:
- 데이터를 생성했지만 조회되지 않음
- 빈 결과 반환
원인:
- 테넌트 컨텍스트가 설정되지 않음
- RLS 정책이 접근을 차단
해결 방법:
-
테넌트 컨텍스트 확인
// 현재 테넌트 확인
dd(tenant());
// 또는
dd(app('tenant')); -
RLS 정책 확인
-- PostgreSQL에서 RLS 정책 확인
SELECT * FROM pg_policies WHERE tablename = 'users'; -
테넌트 컨텍스트 설정
// 명시적 설정
tenancy()->initialize($tenant);
// 또는 미들웨어 확인
Route::middleware(['tenant'])->group(...);
다른 테넌트 데이터 접근 (Cross-Tenant)
증상:
- 다른 테넌트의 데이터가 조회됨 (보안 문제)
원인:
- TenantScope 미적용
- 직접 쿼리로 우회
해결 방법:
-
Model에 Scope 적용 확인
class User extends Model
{
use BelongsToTenant;
} -
직접 쿼리 피하기
// 잘못됨: Scope 우회
DB::table('users')->where('tenant_id', 1)->get();
// 올바름: Eloquent 사용
User::all(); -
테스트로 검증
public function test_tenant_isolation()
{
$tenant1 = Tenant::factory()->create();
$tenant2 = Tenant::factory()->create();
tenancy()->initialize($tenant1);
$user1 = User::factory()->create();
tenancy()->initialize($tenant2);
$this->assertFalse(User::where('id', $user1->id)->exists());
}
성능 문제
느린 쿼리
증상:
- 페이지 로딩이 느림
- 타임아웃 발생
해결 방법:
-
쿼리 로깅 활성화
// AppServiceProvider.php
DB::listen(function ($query) {
Log::info($query->sql, $query->bindings);
}); -
slow query 확인
-- PostgreSQL
SELECT * FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10; -
인덱스 추가
Schema::table('users', function (Blueprint $table) {
$table->index(['tenant_id', 'email']);
}); -
Eager Loading 사용
// N+1 문제
$users = User::all();
foreach ($users as $user) {
echo $user->tenant->name; // 매번 쿼리
}
// 해결
$users = User::with('tenant')->get();
연결 풀 고갈
증상:
SQLSTATE[08006] too many connections
해결 방법:
-
연결 수 확인
SELECT count(*) FROM pg_stat_activity; -
max_connections 증가
# postgresql.conf
max_connections = 200 -
커넥션 풀러 사용
# docker-compose.yml
pgbouncer:
image: edoburu/pgbouncer
environment:
DATABASE_URL: postgres://app:secret@postgres/app
MAX_CLIENT_CONN: 1000
DEFAULT_POOL_SIZE: 20
백업/복원 문제
pg_dump 권한 오류
증상:
pg_dump: error: connection to server failed: FATAL: password authentication failed
해결 방법:
# .pgpass 파일 생성 (권한 600)
echo "postgres:5432:app:app:secret" > ~/.pgpass
chmod 600 ~/.pgpass
# 또는 환경변수 사용
PGPASSWORD=secret pg_dump -h postgres -U app -d app > backup.sql
복원 시 foreign key 오류
증상:
ERROR: insert or update on table "xxx" violates foreign key constraint
해결 방법:
-- 복원 전 FK 비활성화
SET session_replication_role = 'replica';
-- 복원 실행
\i backup.sql
-- FK 다시 활성화
SET session_replication_role = 'origin';
진단 명령어
PostgreSQL 상태 확인
# 연결 테스트
docker exec -it myapp-postgres psql -U app -d app -c "SELECT 1"
# 테이블 목록
docker exec -it myapp-postgres psql -U app -d app -c "\dt"
# 연결 수 확인
docker exec -it myapp-postgres psql -U app -d app -c "SELECT count(*) FROM pg_stat_activity"
Laravel 진단
# DB 연결 테스트
php artisan tinker
>>> DB::connection()->getPdo()
# 마이그레이션 상태
php artisan migrate:status