코드에서 "너무 많은 데이터베이스 요청"을 충족시키는 것은 무엇입니까?


17

이것은 나 자신에 대한 토론이며 일부 동료들이 가지고 있고 여기에 나와서 일반적인 합의가 있는지 어떻게 알 수 있다고 생각했습니다.

기본적으로 데이터베이스 호출에 대한 다음 두 가지 의견이 있습니다. 1. DB 호출 수를 줄이기 위해 필요한 모든 것을 얻기 위해 하나의 큰 호출을 수행하십시오. DB 호출

이것이 특히 실행되는 곳은 일반적인 코드입니다. 우리는 Employee 클래스의 예제를 매우 간단하게 사용할 것입니다.

Employee 클래스에는 10 개의 값 속성 (이름, 성, 고용 날짜 등)이 있고 2 개의 클래스 속성이 있습니다. 1은 부서 클래스를 가리키고 1은 다른 직원 객체를 가리키는 관리자입니다.

사고 방식 # 1에서 직원 데이터와 부서 및 관리자 속성을 채우는 데 필요한 필드 또는 적어도 해당 하위 개체에서 가장 자주 사용되는 필드를 반환하는 한 번의 호출을 수행합니다.

사고 방식 # 2에서 처음에는 직원 개체 만 채운 다음 실제로 요청 된 경우와 시간에 부서 및 관리자 개체 만 채 웁니다.

2의 입장은 매우 간단합니다 ... 요청의 크기를 최소화하고 그러한 요청 중 하나가 이루어질 때마다 얼마나 많은 데이터베이스 객체가 적중해야 하는지를 최소화합니다. # 1의 입장은 제대로 구현 될 수 있다고해도 코드가 여러 연결을 만들어야한다는 사실은 웹 서버와 데이터베이스 간의 연결을 줄이는 대신 더 많은 변형을 유발한다는 것입니다.

이 연구의 원동력은 웹 서버와 데이터베이스 서버 사이의 트래픽이 제어 할 수 없다는 것입니다.


7
내 경험상 이것에 대한 "정답"은 없습니다. 대기 시간과 처리량 사이에는 균형이 있습니다. 낮은 대기 시간은 많은 작은 요청 또는 하나의 큰 요청을 허용 할 수 있습니다. 그러나 대기 시간이 길면 많은 양의 데이터를 한 번에 이동하는 것이 더 좋습니다. 그럼에도 불구하고 대기 시간이 긴 구성에서 처리량이 낮은 경우 작은 청크를 가져와 응답 속도를 높이는 것이 좋습니다.

3
아마도 n + 1 문제와 관련이있을 것입니다 stackoverflow.com/questions/97197/…
Valera Kolupaev

@Valera : 여기에 편의를 위해 그 질문에 게시 된 링크입니다 : realsolve.co.uk/site/tech/hib-tip-pitfall.php?name=n1selects
rwong

4
"웹 서버와 데이터베이스 서버 간의 트래픽 양이 통제 할 수 없습니다." 그게 무슨 뜻이야? 실제 문제가 무엇인지 구체적 으로 설명 할 수 있습니까 ? 성능 문제가 있습니까? 프로파일 링 및 측정을 수행 했습니까? 실제 측정 결과를 문제의 일부로 제공하십시오. 그렇지 않으면, 우리는 단지 추측하고 있습니다.
S.Lott

답변:


8

이 질문의 원동력이 너무 많은 트래픽 인 경우 자주 사용하는 객체를 캐싱하는 것을 보셨습니까? 예를 들어 : Employee 및 Department 및 Supervisor 객체를 얻은 후에 가까운 시일에 다시 요청하면 이미 캐시 상태이므로 검색 할 필요가 없도록 캐시를 추가하는 것이 좋습니다. 다시. 물론, 캐시는 거의 사용되지 않는 객체가 만료되도록해야하며, 응용 프로그램에 의해 수정되어 데이터베이스에 다시 저장된 객체를 제거 할 수 있어야합니다.

사용중인 언어 및 프레임 워크에 따라 필요한 것 (또는 대부분)을 수행 할 수있는 캐싱 프레임 워크가 이미있을 수 있습니다. Java를 사용하는 경우 Apache Commons-Cache를 살펴볼 수 있습니다 (한동안 사용하지 않았으며 휴면 상태이지만 여전히 사용할 수 있으며 마지막으로 사용했을 때 꽤 괜찮 았습니다).


3

무언가를 처음 쓸 때는 항상 가독성과 명료 함을 유지 하십시오. 그런 다음 필요할 때 언제든 리팩토링 할 수 있습니다. 병목 현상을 찾기 위해로드 테스트를 수행하십시오. 많은 경우 문제를 일으키는 호출 횟수가 아니라 잘못 작성된 호출이 있습니다.

너무 많은 분류는 응용 프로그램에 따라 다릅니다. 대부분의 웹 응용 프로그램에서 30 초 미만은 허용됩니다. 나는 당신의 사용자들에게 그들의 기대에 대해 이야기하고 싶습니다.


잘못 작성된 DB 호출은 무엇입니까?
nu everest

3

귀하의 질문은 주어진 페이지에 어떤 데이터가 필요할지 추측해야한다는 가정에 근거한 것 같습니다. 그렇지 않습니다. 순진한 접근 방식만큼 쉽지는 않지만 코드를 설계하여 데이터베이스를 호출하기 전에 부서 또는 감독자 속성이 필요한지 알 수 있습니다.


3

이것들은 내가 사용하는 규칙입니다. 어쩌면 그들은 당신에게 유용 할 것입니다.

  1. 먼저 측정하십시오! 실제로 해당 리소스로 트래픽이 흐르는 것을 볼 수없고 해당 리소스가 느리게 응답하지 않는 한 "느려질 수있는"코드는 보지 않을 것입니다.
  2. 1 요청 = K 쿼리. 데이터베이스와 통신하는 횟수는 요청 된 리소스 종류에 따라 완전히 결정됩니다. 그 자원의 요청이나 상태의 본질에 의해 결코; 귀하의 예에서, 아마도 최대 3 개의 쿼리 일 것입니다. 1은 직원, 1은 부서, 1은 감독자; 각각 몇 개가 발생하는지는 중요하지 않습니다.
  3. 사용하지 않는 것을 쿼리하지 마십시오 . 이것이 우리가 말하는 HTTP라면, 나중에 데이터를 쿼리하는 것은 의미가 없습니다. 더 이상 없습니다; 각 요청은 깨끗한 슬레이트에서 시작됩니다. 때로는 테이블에서 대부분 의 열이 필요 하지만 때로는 하나 또는 두 개만 필요합니다. 내가 필요한 분야를 정확히 알면 바로 물어볼 것입니다.
  4. 문제에 하드웨어를 던지십시오. 서버는 싸다. 때로는 데이터베이스를보다 강력한 상자로 옮기는 것만으로도 충분한 성능을 얻을 수 있습니다. 또는 일부 쿼리를 읽기 전용 복제본으로 보냅니다.
  5. 먼저 캐시를 무효화 한 다음 캐싱을 구현하십시오. 캐시에 자주 사용되거나 쿼리하기 어려운 데이터를 넣는 충동은 강력합니다. 그러나 사용하지 않는 데이터를 제거하거나 대체 된 데이터가 만료되는 경우가 종종 있습니다. 캐시에서 데이터를 가져 오는 방법을 알고 있다면; 그러면 캐시에 안전하게 넣을 수 있습니다. 캐시를 무효화하는 것이 쿼리를 수행하는 것보다 비용이 더 많이 든다면; 캐시가 필요하지 않았습니다.

2

이 두 가지 전략 모두 완벽하게 유효합니다. 각각의 장단점이 있습니다 :

3 개의 객체 모두에 대해 한 번의 호출 :

  • 더 빨리 수행됩니다
  • 필요한 경우 정확히 필요한 것을 얻을 수 있습니다.
  • 아마도 한 경우에만 사용할 수 있습니다 (매우 일반적인 경우 일 수 있음)
  • 유지하기가 더 어려울 것입니다
  • 3 개 개체의 스키마 또는 필요한 데이터가 변경되면 변경되므로 더 자주 유지 관리해야합니다.

객체 당 한 번의 호출 (총 3 번의 호출)

  • 각 객체 유형의 단일 인스턴스를 채우는 범용 호출을 제공합니다. 그들은 독립적으로 사용할 수 있습니다
  • 쿼리 구조가 단순 해져 유지 관리가 쉬워집니다.
  • 속도가 느려집니다 (3 배 느릴 필요는 없지만 동일한 데이터에 대해 오버 헤드가 증가 함)
  • 불필요한 데이터를 검색 할 때 문제가 발생할 수 있습니다 (한 필드가 필요할 때 전체 레코드를 낭비하는 것은 낭비입니다)
  • 단일 레코드 쿼리가 콜렉션의 레코드 당 하나씩 N 회 전송되면 다 대일 관계가 존재할 때 N + 1 문제가 발생할 수 있습니다.

두 가지 우려 사항 (두 번째 목록의 3 번과 5 번)에 대한 응답으로 ... 감독자와 부서가 1/3 (또는 그 이하)로만 사용된다면 어떨까요? List <> 객체를 포함하도록 코딩 된 List <> 객체를 처음 참조하자마자 코드가 모든 어린이를 가져 오도록 설계된 경우 어떻게됩니까? ... 그러면 대부분의 조심성이 완화됩니까?
user107775

보조 개체가 거의 필요하지 않은 경우 일반적으로이 경우 성능이 더 빠르지 만 (검색 할 데이터가 적음) 최악의 경우 속도가 느려집니다 (컴퓨터에서 통신 오버 헤드의 3 배를 사용하여 동일한 데이터 또는 더 많이 검색 됨). N + 1 문제의 경우 관계의 "한 쪽"에 대한 외래 키를 기반으로 수행 할 수있는 개체 목록을 검색하는 쿼리를 설계 한 다음 여러 행을 가져 오기만하면됩니다. 쿼리 결과에서 레코드의 기본 키가 있어야하는 버전의 쿼리를 사용할 수 없습니다.
KeithS

1

나에게, 너무 많은 DB 요청이 주어진 시간에 필요한 데이터를로드하는 데 필요한 것보다 많은 요청을하고 있습니다.

따라서 데이터가 필요하지 않으며 나중에 두 번째 여행을 피하기 위해 메모리를 낭비하지 마십시오. 그러나 데이터 양이 필요한 경우 db에 대한 호출을 최소화해야합니다.

따라서 두 가지 옵션이 모두 있으며 상황에 맞는 옵션을 사용하십시오.

편집 :이 과정은 상황에 따라 다릅니다. 예를 들어 웹 애플리케이션의 경우 웹 전체의 웹 애플리케이션과 달리 웹 애플리케이션이 네트워크 내에서 DB에 액세스하는 데스크탑 앱의 경우와 다르게 고려해야합니다.


공통 코드를 작성하고 코드가 사용될 방식이 확실하지 않은 경우 어떻게해야합니까? 어쩌면 관리자가 필요없는 사람을 구상하지는 않겠지 만 작업중인 응용 프로그램 만 필요하다는 것이 밝혀졌습니다. 물론, 별도의 함수를 작성할 수 있습니다 ... 하나는 포함하지 않고 다른 하나는 포함 시키지만 공통 코드는 어느 시점에서 사용하기 위해 너무 많은 지식이 필요합니까?
user107775

@ user107775 나는 보통 각 경우에 두 개의 함수 만 작성한다. 하나는 속성 값만 반환하고 다른 하나는 모든 관련 클래스가있는 클래스를 반환합니다. 대부분의 시간이기 때문에 속성 만 필요하기 때문입니다. 이런 식으로, 당신은 세부 지식이 필요하지 않습니다. 하나는 기본 사항과 다른 모든 것을 얻습니다. 나는 그것이 합리적인 균형이라고 생각합니다. 그러나 일부 특수한 경우에는 더 많은 최적화가 필요하지만 경우에 따라 다릅니다.
AJC

1

DB에 연결하여 요청을 전송하고 구문 분석하면 일반적으로 결과 검색에 비해 상당한 시간이 걸리므로 전체 추세는 한 요청에서 가능한 많은 쿼리를 연결하는 것입니다.

그래도 한 번에이 작업을 수행하면 코드를 유지 관리 할 수 ​​없게됩니다. 대신, 일반적으로 추가 추상화 계층에 의해 달성됩니다. 코드는 요청에 따라 여러 요청을 예약 한 다음 엔진이이를 하나의 큰 요청으로 분석하고 (필요한 경우 캐시 사용) 응답을 필요에 따라 발송합니다.

물론 모든 쿼리를 하나의 쿼리에서 항상 검색 할 수있는 것은 아닙니다. 다음 쿼리를 작성하는 데 필요한 데이터를 제공하는 쿼리가있는 경우가 많으므로 반복해야합니다. 여전히 많은 쿼리 번들을 처리하고 한 번에 최대한 많은 성능을 수행하는 것이 데이터베이스에 대한 수백 개의 작은 샷보다 낫습니다.

따라서 필요한 것을 계획하고 요청 및 검색하고, 더 필요한 경우 다시 요청한 후 검색 한 다음 데이터를 생성하여 컨텐츠를 생성하십시오. 코드 전체에 흩어져있는 로컬 변수 초기화와 같은 데이터베이스 요청을 사용하지 마십시오.


1

우리는 귀하가 어떤 선택을 너무 빨리 최적화해야하는지 아는 응용 프로그램에 대해 충분히 알지 못합니다. Supervisor 데이터는 얼마나 자주 사용됩니까? 그것은 낭비 일 수있는 것처럼 보이지만 우리는 모른다. 분리 된 상태로 유지하면 시스템을 모니터링하여 이들이 얼마나 자주 함께 사용되는지 확인할 수 있습니다. 한 번의 통화로 결합하기로 결정할 수있는 것보다. 그렇지 않으면,이 큰 전화로 병목을 만들기 시작하면 어디에서 문제 해결을 시작합니까? 생략해야하는 것이 무엇인지 파악하기가 어렵습니다. 이 프로세스에 더 많은 데이터 필드가 추가 될 수 있습니다.

DB 메모리와 디스크에서이 중 어느 정도가 나오는지 아는 것이 흥미로울 것입니다. 주소에 비해 부서가 변경 될 가능성이 거의 없다고 느끼지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.