본문으로 건너뛰기

데이터베이스 문제

데이터베이스 관련 문제와 해결 방법입니다.

연결 문제

SQLSTATE[HY000] Connection refused

증상:

SQLSTATE[HY000] [2002] Connection refused

원인:

  • PostgreSQL 컨테이너가 시작되지 않음
  • 잘못된 호스트/포트 설정
  • 네트워크 연결 문제

해결 방법:

  1. 컨테이너 상태 확인

    make status NAME=myapp
  2. PostgreSQL 컨테이너 로그 확인

    docker logs myapp-postgres
  3. .env 설정 확인

    # .env
    DB_CONNECTION=pgsql
    DB_HOST=postgres # 컨테이너 이름 사용
    DB_PORT=5432 # 컨테이너 내부 포트
    DB_DATABASE=app
    DB_USERNAME=app
    DB_PASSWORD=secret
  4. 네트워크 확인

    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

원인:

  • 마이그레이션 파일 중복 실행
  • 마이그레이션 상태 불일치

해결 방법:

  1. 마이그레이션 상태 확인

    docker exec -it myapp-web php artisan migrate:status
  2. 특정 마이그레이션 롤백

    docker exec -it myapp-web php artisan migrate:rollback --step=1
  3. 마이그레이션 테이블 확인

    SELECT * FROM migrations ORDER BY batch DESC;
주의

migrate:fresh는 모든 데이터를 삭제합니다. 운영 환경에서 절대 사용하지 마세요.


Nothing to migrate

증상:

Nothing to migrate.

원인:

  • 모든 마이그레이션이 이미 실행됨
  • 마이그레이션 파일이 없음

해결 방법:

  1. 마이그레이션 상태 확인

    php artisan migrate:status
  2. 새 마이그레이션 파일 확인

    ls -la database/migrations/

RLS (Row-Level Security) 문제

데이터가 보이지 않음

증상:

  • 데이터를 생성했지만 조회되지 않음
  • 빈 결과 반환

원인:

  • 테넌트 컨텍스트가 설정되지 않음
  • RLS 정책이 접근을 차단

해결 방법:

  1. 테넌트 컨텍스트 확인

    // 현재 테넌트 확인
    dd(tenant());

    // 또는
    dd(app('tenant'));
  2. RLS 정책 확인

    -- PostgreSQL에서 RLS 정책 확인
    SELECT * FROM pg_policies WHERE tablename = 'users';
  3. 테넌트 컨텍스트 설정

    // 명시적 설정
    tenancy()->initialize($tenant);

    // 또는 미들웨어 확인
    Route::middleware(['tenant'])->group(...);

다른 테넌트 데이터 접근 (Cross-Tenant)

증상:

  • 다른 테넌트의 데이터가 조회됨 (보안 문제)

원인:

  • TenantScope 미적용
  • 직접 쿼리로 우회

해결 방법:

  1. Model에 Scope 적용 확인

    class User extends Model
    {
    use BelongsToTenant;
    }
  2. 직접 쿼리 피하기

    // 잘못됨: Scope 우회
    DB::table('users')->where('tenant_id', 1)->get();

    // 올바름: Eloquent 사용
    User::all();
  3. 테스트로 검증

    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());
    }

성능 문제

느린 쿼리

증상:

  • 페이지 로딩이 느림
  • 타임아웃 발생

해결 방법:

  1. 쿼리 로깅 활성화

    // AppServiceProvider.php
    DB::listen(function ($query) {
    Log::info($query->sql, $query->bindings);
    });
  2. slow query 확인

    -- PostgreSQL
    SELECT * FROM pg_stat_statements
    ORDER BY total_time DESC
    LIMIT 10;
  3. 인덱스 추가

    Schema::table('users', function (Blueprint $table) {
    $table->index(['tenant_id', 'email']);
    });
  4. 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

해결 방법:

  1. 연결 수 확인

    SELECT count(*) FROM pg_stat_activity;
  2. max_connections 증가

    # postgresql.conf
    max_connections = 200
  3. 커넥션 풀러 사용

    # 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

관련 문서