2016-12-30 8 views
1

을 복용.Laravel orWhere()/MySQL을 또는 쿼리 내가 Laravel 4.2을 사용하고 있는데 내 응용 프로그램이 여러 위치에 걸쳐 재고를 추적하는 데 사용되는 시간이 오래

는 데이터베이스 레코드가 속하는 명세 품목 및 위치 모두를 참조하는 동안 양의 값을 포함하는 inventory_items 테이블 inventory_locations 표 그들 사이 inventory_items_inventory_location 피봇 테이블로 설정된다. 다음 SQL을 제공

InventoryItem::whereHas('inventoryLocations', function($q) { 
    $q->where('reserved', '>=', 0) 
    ->orWhere('available', '>=', 0) # slow 
    ->orWhere('inbound', '>=', 0) # slow 
    ->orWhere('total', '>=', 0); # slow 
})->toSql(); 

:

내 쿼리 내가 하위 쿼리 및 orWhere과 같이 사용하고 Laravel에서 0보다 이상 동일한 어떤 위치 수량 값을 재고 항목을 찾을 수 있습니다 :

select * from `inventory_items` 
where `inventory_items`.`deleted_at` is null 
and (
    select count(*) from `inventory_locations` 
    inner join `inventory_item_inventory_location` 
    on `inventory_locations`.`id` = `inventory_item_inventory_location`.`inventory_location_id` 
    where `inventory_item_inventory_location`.`inventory_item_id` = `inventory_items`.`id` 
    and `reserved` >= ? 
    or `available` >= ? # slow 
    or `inbound` >= ? # slow 
    or `total` >= ? # slow 
) >= 1 

문제는 (#slow에 의해 코드에 표시) or 문으로 쿼리 시간이 더 내 Laravel 응용 프로그램 (또는 장인 어설프게을 통해)을 통해 5 초보다, 직접 프로 속편으로 1 초에 달려 있다는 것입니다. 이 '또는'수표가 없으면 (예 : '예약'과 같은 수량 유형 만 확인) 쿼리는Sequel Pro에서 100ms이고 앱/팅커에서 유사합니다. 이러한 추가 '또는'검사를 추가하는 이유

잘 모르겠어요 쿼리에 너무 많은 시간을 추가합니다. 어떤 아이디어가 더 performant 검색어를 만드는 방법?

+1

당신은 테이블의'reserved','available','inbound','total' 필드에 인덱스를 추가 한? – num8er

+0

일반적으로 "또는"조건에서 쿼리를 실행할 수 있습니다. 또한 이러한 유형의 동적 조건을 사용할 때 데이터베이스 엔진은 정적 경로를 만들지 않습니다. 그래서 –

+0

num8er @보다 더 많은 시간이 걸릴 수 있습니다 - 수를 간단한 예를 들어 주시겠습니까? –

답변

3

는 결과 쿼리와 조건을 참조하십시오. 난 당신이

where `inventory_item_inventory_location`.`inventory_item_id` = `inventory_items`.`id` 
and (
    `reserved` >= ? 
    or `available` >= ? # 
    or `inbound` >= ? 
    or `total` >= ? 
) 

대신

그것은 행의 높은 양의 테이블 대단히 느린 전체 테이블 스캔 결과
where `inventory_item_inventory_location`.`inventory_item_id` = `inventory_items`.`id` 
and `reserved` >= ? 
or `available` >= ? # slow 
or `inbound` >= ? # slow 
or `total` >= ? 

입니다 필요 추측으로 당신은 확실히, 거기에 약간의 브래킷을 그리워. 이 문제를 해결하기 위해

, 대체

InventoryItem::whereHas('inventoryLocations', function($q) { 
    $q->where(function($subquery) { 
    $subquery->where('reserved', '>=', 0) 
    ->orWhere('available', '>=', 0) 
    ->orWhere('inbound', '>=', 0) 
    ->orWhere('total', '>=', 0); 
    }); 
})->toSql(); 

체크 아웃하면 조회 할 방법 쿼리가 실행됩니다 얼마나 많은 행을 분석 할 수 있습니다 MySQL을의 EXPLAIN 명령을 가진

InventoryItem::whereHas('inventoryLocations', function($q) { 
    $q->where('reserved', '>=', 0) 
    ->orWhere('available', '>=', 0) # slow 
    ->orWhere('inbound', '>=', 0) # slow 
    ->orWhere('total', '>=', 0); # slow 
})->toSql(); 

- http://dev.mysql.com/doc/refman/5.7/en/explain.html

+0

완벽 - 지금 서브 쿼리하는 것이 의미가 있습니다. 어떻게 작동하는지 조금 더 알게되었습니다. 앞으로 이런 종류의 문제를 디버깅하는 방법을 설명 할 것입니다. 감사 –