2019년 3월 25일 월요일

#7 Django 쿼리와 데이터베이스 레이어

📩쿼리와 데이터베이스 레이어


다른 ORM과 마찬가지로 장고는 여러종류의 데이터를 DB종류와는 독립적인 형태로 객체화

그리고 상호작용가능한 메서드 제공


7.1  단일 객체를 가져와서 작업하는 detail뷰에서는 

      get()대신get_object_or_404()를 이용하자

       단! get_object_or_404()는 오직 views에서만 이용한다


7.2 예외를 일으킬수 있는 쿼리를 주의해서 예외처리를 해주자


        Error에 대해서

        ObjectDoesNotExist는 어떤 모델객체에서도 이용가능하지만
        DoesNotExist는 특정 모델에서의 존재 유무에서만 이용가능

        여러개의 객체가 반환된다면

        MultipleObjectsReturned


7.3 쿼리를 좀더 명확하게 하기위해 지연 연산 이용

        장고의 ORM은 강력하기에 코드를 명확하게 해야한다.
        복잡한 쿼리의 경우 몇줄 안되는 코드에 너무 많은 기능을 우겨넣지 말자

        지연 연산은 데이터가 정말로 필요하기 전까지 장고가 SQL을 호출하지 않는 특징
        따라서 ORM메서드와 함수를 원하는 만큼 연결해서 코드를 짤수 있는데
        결과를 실행하기전까지 DB와 연동되지 않기때문이다
        따라서 한줄에 우겨넣던것을 여러줄에 쓸수있다.

        자동으로 나눠서 사용하면 지연연산 적용된다



고급쿼리도구 이용하기

    ORM으로 처리된 데이터를 다른 프로그래밍언어를 통해처리하는것보다
    DB가 처리하는것이 더 빠르므로 고급 쿼리도구를 이용해 DB와 Django사이에 지속적인 테스트를 수행한다

    만약 Python으로 처리하게 되면 느리고 메모리 소모도 많아지며
    race condition이 걸려 공유 자원에 대해 여러 프로세스가 접근해 데이터 분실이 생길수 있다.

쿼리표현식을 꼭 익혀두자 안정성과 성능의 향상을 가져올것이다


데이터베이스 함수 이용

    UPPER(), LOWER(), COALESCE(), CONCAT(), LENGTH(), SUBSTR()등의 데이터함수를 이용할수있는데

    이용이 매우쉽고 간결하며 성능향상을 가져올 뿐만 아니라 DB별로 다른 함수들을 장고 ORM이 통합해줘 다른 DB의 코드도 잘 작동


7.5 필수 불가결한 상황이 아니라면 rowSQL은 지양하자


    보안, 유효성 검사등 여러 이점이 있으니 ORM을 이용하자
    앱이 서드파티 패키지로 릴리스 될때에도 로우 SQL은 이식성이 떨어진다

    로우 SQL은 사용할때 코드가 월등히 간결해지고 단축되는 경우에만
    (ex : 큰 데이터 셋에 적용되는 다수의 쿼리셋 연동)


7.6 필요에따라 인덱스를 이용하자


    db_index = True를 추가하면 되는데

    인덱스가 빈번하게 이용될때 (모든 쿼리의 10~25% 사이)
    실제 데이터또는 비슷한 데이터가 존재해서 인덱싱 결과에 대한 분석이 가능할때
    인덱싱을 통해 성능이 향상되는지 테스트 할수 있을때

    ==> 인덱스를 추가하자


7.7 트랜잭션


ORM이 쿼리를 호출할때 자동 커밋을 해주는것으로 인해 처리과정에서 둘 이상의 DB의 수정이 요구되면 두번쨰 수정에서 DB상의 충돌이 일어날수있는데

트랜잭션을 이용하면 해결할수 있다

DB트랜잭션이란 둘 또는 이상의 DB UPDATE를 단일화된 작업으로 처리하는 기법
즉 하나의 수정작업이 실패하면 트랜잭션상의 모든 업데이트가 실패

이를 제대로 이용하기위해서는 DB가 ACID(Atomic, Consistent, Isolated, Durable)을 가져야한다

    
     HTTP요청을 트랜잭션으로 처리하자

    settings/base.py 에 있는
    DATABASES = {
    'ATOMIC_REQUESTS' : True,
    }
 
    설정을 해주게 되면 모든 웹 요청을 트랜잭션으로 쉽게 처리해줄수 있다.
    
    위의 설정은 모든 DB쿼리가 보호되는 안정성을 얻을수 있는 반면 DB의 디자인 잠금처리에 따라 다른 성능저하를 보여줄수 있다.
    이러한 설정은 DB의 무결성을 유지하는데 효과적이지만 트래픽이 많아지면 별로다

     또한 에러가 발생하고 나서 롤백되므로 처리된 작업에 대한 메일 발송 등과 같은 경우에는(DB가 아닌 item에 대해 create update delete하는 경우에는)
     뷰를 transaction.non_atomic_requests()로 해주자
     하지만 성능문제가 정말 심각하지 않는 이상 ATOMIC_REQUESTS 를 이용하자


   명시적 트랜잭션 선언

   트랜잭션에서 어떤 뷰, 비지니스 로직이 얽혀있는지 명시해주는 것으로 많은 개발시간을 요한다.

 
   가이드라인

   - DB에 변경이 생기지 않는 DB작업은 트랜잭션으로 처리 X
   
   - DB에 변경이 생기는 것은 반드시 트랜잭션처리

   - DB 읽기를 하는 DB변경작업 또는 성능관련 경우에는 트랜잭션 처리와 비처리를 둘다고려


  트랜잭션 처리하는 ORM
  
  생성 : .creata(), .bulk_create(), .get_or_create()

  수정 : .update()

  삭제 : .delete()


  트랜잭션 처리 X ORM

  가져오기 : .get(), .filter(), .count(), .iterate(), .exists(), .exclude(), .in_bulk() 등
 

  단 독립적인 ORM 은 자체적으로 트랜잭션 처리를 하기때문에

      여러 ORM들을 뷰나 함수 or 메서드에서 호출할때 트랜잭션 처리를 해주자


  django.http.StreamingHttpResponse와 트랜잭션

  위의 응답 메서드를 사용하면 ATOMIC_REQUESTS 를 둘중 하나에 맞게 설정하자

  1. ATOMIC_REQUESTS의 장고 기본값을 False로 설정

  2. 뷰를 django.db.transaction.non_atomic_requests 데코레이터로 감싸자

  트랜잭션은 뷰에서만 적용이 된다

  위의 메서드와 트랜젝션은 당장은 사용을 안하고 모르겠지만 나중을 위한 참고용으로 남겨둔다


  MySQL에서의 트랜잭션

  MYSQL 의 DB type이 InnoDB인가 MyISAM인가에 따라 트랜잭션의 주원여부가 달라지낟

  트랜잭션이 지원되지 않으면 장고는 늘 오토커밋모드로 작동한다

  더 많은 정보를 원한다면
  http://2scoops.co/1.8-transactions-in-mysql
  http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html


  장고 ORM 과 트랜잭션 자료

  장고 공식 문서에 transaction부분을 참고 하거나

  Real Python 에서 transaction부분을 찾아보자


댓글 없음:

댓글 쓰기

가장 많이 본 글