짧은 답변
세 번째 옵션 : Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement
$teamMorphType = Relation::getMorphedModel('team');
$groupMorphType = Relation::getMorphedModel('group');
$formMorphType = Relation::getMorphedModel('form');
$permissible = [
$teamMorphType => [$user->team_id],
$groupMorphType => [],
$formMorphType => [],
];
foreach ($user->permissible as $permissible) {
switch ($permissible->permissible_type) {
case $teamMorphType:
case $groupMorphType:
case $formMorphType:
$permissible[$permissible->permissible_type][] = $permissible->permissible_id;
break;
}
}
$forms = Form::query()
->where('user_id', '=', $user->id)
->orWhereIn('id', $permissible[$fromMorphType])
->orWhereIn('team_id', $permissible[$teamMorphType])
->orWhereIn('group_id', $permissible[$groupMorphType])
->get();
긴 대답
한편으로는 코드에서 수행 할 수있는 모든 작업이 쿼리에서 수행하는 것보다 성능면에서 더 좋습니다.
반면, 필요 이상으로 데이터베이스에서 더 많은 데이터를 가져 오면 이미 너무 많은 데이터 (RAM 사용 등)가됩니다.
내 관점에서 볼 때 사이에 무언가가 필요하며 숫자에 따라 균형이 어디에 있는지 알 수 있습니다.
제안한 마지막 옵션 인 몇 가지 쿼리를 실행하는 것이 좋습니다.Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement
).
- 모든 권한에 대해 모든 식별자 쿼리 (5 개의 쿼리)
- 모든 양식 결과를 메모리에 병합하고 고유 한 값을 얻습니다.
array_unique($ids)
- IN () 문의 식별자를 사용하여 양식 모델을 쿼리하십시오.
몇 가지 도구를 사용하여 쿼리를 여러 번 실행하여 제안한 세 가지 옵션을 시도하고 성능을 모니터링 할 수 있지만 마지막 옵션이 최상의 성능을 제공 할 것이라고 99 % 확신합니다.
사용중인 데이터베이스에 따라 많은 변화가있을 수 있지만, 예를 들어 MySQL에 대해 이야기하는 경우; 매우 큰 쿼리에서 더 많은 데이터베이스 리소스를 사용하면 단순한 쿼리보다 더 많은 시간을 소비 할뿐만 아니라 쓰기에서 테이블을 잠 그게되어 교착 상태 오류가 발생할 수 있습니다 (슬레이브 서버를 사용하지 않는 경우).
반면에 양식 ID의 수가 너무 많으면 너무 많은 자리 표시 자에 대해 오류가 발생할 수 있으므로 500 개의 ID 그룹으로 쿼리를 청크하고 싶을 수 있습니다. (바인딩 수가 아닌 크기) 및 결과를 메모리에 병합합니다. 데이터베이스 오류가 발생하지 않더라도 성능에 큰 차이가있을 수 있습니다 (아직 MySQL에 대해 이야기하고 있습니다).
이행
이것이 데이터베이스 체계라고 가정합니다.
users
- id
- team_id
forms
- id
- user_id
- team_id
- group_id
permissible
- user_id
- permissible_id
- permissible_type
이미 구성된 다형성 관계가 허용됩니다. 됩니다.
따라서 관계는 다음과 같습니다.
- 자신의 형태 :
users.id <-> form.user_id
- 팀 소유 양식 :
users.team_id <-> form.team_id
- 양식을 소유 한 그룹에 대한 권한이 있습니다.
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
- 양식을 소유 한 팀에 대한 권한이 있습니다.
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
- 양식에 대한 권한이 있습니다.
permissible.user_id <-> users.id && permissible.permissible_type = 'App\From'
단순화 버전 :
$teamMorphType = Relation::getMorphedModel('team');
$groupMorphType = Relation::getMorphedModel('group');
$formMorphType = Relation::getMorphedModel('form');
$permissible = [
$teamMorphType => [$user->team_id],
$groupMorphType => [],
$formMorphType => [],
];
foreach ($user->permissible as $permissible) {
switch ($permissible->permissible_type) {
case $teamMorphType:
case $groupMorphType:
case $formMorphType:
$permissible[$permissible->permissible_type][] = $permissible->permissible_id;
break;
}
}
$forms = Form::query()
->where('user_id', '=', $user->id)
->orWhereIn('id', $permissible[$fromMorphType])
->orWhereIn('team_id', $permissible[$teamMorphType])
->orWhereIn('group_id', $permissible[$groupMorphType])
->get();
자세한 버전 :
// Owns Form
// users.id <-> forms.user_id
$userId = $user->id;
// Team owns Form
// users.team_id <-> forms.team_id
// Initialise the array with a first value.
// The permissions polymorphic relationship will have other teams ids to look at
$teamIds = [$user->team_id];
// Groups owns Form was not mention, so I assume there is not such a relation in user.
// Just initialise the array without a first value.
$groupIds = [];
// Also initialise forms for permissions:
$formIds = [];
// Has permissions to a group that owns a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
$teamMorphType = Relation::getMorphedModel('team');
// Has permissions to a team that owns a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
$groupMorphType = Relation::getMorphedModel('group');
// Has permission to a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Form'
$formMorphType = Relation::getMorphedModel('form');
// Get permissions
$permissibles = $user->permissible()->whereIn(
'permissible_type',
[$teamMorphType, $groupMorphType, $formMorphType]
)->get();
// If you don't have more permissible types other than those, then you can just:
// $permissibles = $user->permissible;
// Group the ids per type
foreach ($permissibles as $permissible) {
switch ($permissible->permissible_type) {
case $teamMorphType:
$teamIds[] = $permissible->permissible_id;
break;
case $groupMorphType:
$groupIds[] = $permissible->permissible_id;
break;
case $formMorphType:
$formIds[] = $permissible->permissible_id;
break;
}
}
// In case the user and the team ids are repeated:
$teamIds = array_values(array_unique($teamIds));
// We assume that the rest of the values will not be repeated.
$forms = Form::query()
->where('user_id', '=', $userId)
->orWhereIn('id', $formIds)
->orWhereIn('team_id', $teamIds)
->orWhereIn('group_id', $groupIds)
->get();
사용 된 자원 :
데이터베이스 성능 :
- 데이터베이스에 대한 쿼리 (사용자 제외) : 2 ; 하나는 허용되며 다른 하나는 양식을 가져옵니다.
- 조인이 없습니다 !!
- 가능한 최소의 논리합 (
user_id = ? OR id IN (?..) OR team_id IN (?...) OR group_id IN (?...)
.
메모리, PHP 성능 :
- foreach 내부 의 스위치로 루프를 반복하십시오 .
array_values(array_unique())
ID 반복을 피하기 위해.
- 메모리에, IDS 3 개 어레이 (
$teamIds
, $groupIds
, $formIds
)
- 메모리에서 관련 권한 웅변 수집 (필요한 경우 최적화 할 수 있음).
장점과 단점
장점 :
- 시간 : 단일 쿼리 시간의 합계는 조인 및 OR이있는 큰 쿼리 시간보다 짧습니다.
- DB 리소스 : join 및 / 또는 문이있는 쿼리에서 사용하는 MySQL 리소스는 별도의 쿼리 합계에서 사용되는 것보다 큽니다.
- 돈 : PHP 리소스보다 비싼 데이터베이스 리소스 (프로세서, RAM, 디스크 읽기 등)가 적습니다.
- 잠금 : 읽기 전용 슬레이브 서버를 쿼리하지 않는 경우 쿼리에서 더 적은 행 읽기 잠금을 만듭니다 (읽기 잠금은 MySQL에서 공유되므로 다른 읽기는 잠그지 않지만 쓰기는 차단합니다).
- 확장 성 :이 방법을 사용하면 쿼리 청크와 같은 성능을 최적화 할 수 있습니다.
단점 :
- 코드 리소스 : 데이터베이스가 아닌 코드로 계산하면 코드 인스턴스, 특히 RAM에서 더 많은 리소스가 소비되므로 중간 정보가 저장됩니다. 우리의 경우, 이것은 단지 ID의 배열 일 것입니다. 실제로 문제가되지는 않습니다.
- 유지 관리 : Laravel의 속성 및 방법을 사용하고 데이터베이스를 변경하면보다 명시적인 쿼리 및 처리를 수행하는 것보다 코드를 업데이트하는 것이 더 쉽습니다.
- 과잉? : 경우에 따라 데이터가 크지 않은 경우 성능 최적화가 과도 할 수 있습니다.
성능 측정 방법
성능을 측정하는 방법에 대한 단서가 있습니까?
- 느린 쿼리 로그
- 분석 테이블
- 테이블 상태 표시처럼
- 설명 ; 확장 된 EXPLAIN 출력 형식 ; Explain 사용 ; 출력 설명
- 경고 표시
흥미로운 프로파일 링 도구 :