2016-12-22 3 views
0

나는 Hibernate에서 MySQL 데이터베이스를 사용하도록 스프링 부트 프로젝트를 설정했다. 최근에 데이터베이스 테이블에 30,000 개의 새 항목을 추가했으며 그 이후로 쿼리가 심하게 느려졌습니다.봄 데이터 쿼리가 매우 느림

저는 쿼리 DSL을 사용하여 쿼리를 직접 수행합니다.

@Entity 
@Table(name = "Candidates", schema = "Candidate") 
public class Candidate { 

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
@Column(name = "CandidateID") 
private Long candidateID; 
@Column(name = "FirstName") 
private String firstName; 
@Column(name = "LastName") 
private String lastName; 
@Column(name = "Zip") 
private String zip; 
@Column(name = "Email") 
private String email; 

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "candidate") 
private List<CandidateField> fields; 

//Constructors, getters, setters omitted 

CandidateField 엔티티 : 나는 CandidateField 엔티티와 OneToMany 관계를 다음과 같은 후보의 실체가 있다고 가정

@Autowired 
CandidateRepository repository; 
QCandidate candidate = QCandidate.candidate; 
BooleanExpression predicate = candidate.fields.any().name.eq("Accounting"); 
Iterable<Candidate> results = repository.findAll(predicate); 

: 마지막으로, 여기

@Entity 
@Table(name = "CandidateFields", schema = "Candidate") 
public class CandidateField { 

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
@Column(name = "CandidateFieldID") 
@JsonIgnore 
private Long candidateFieldID; 
@JsonIgnore 
@Column(name = "CandidateID") 
private Long candidateID; 
@Column(name = "Name") 
private String name; 
@ManyToOne 
@JoinColumn(name = "CandidateID", referencedColumnName = "CandidateID", insertable = false, updatable = false) 
@JsonIgnore 
private Candidate candidate; 

//Constructors, getters, setters omitted 

그리고 나의 검색 코드 마지막 행은 80 행의 결과와 함께 30k 레코드 데이터베이스 (필드가 인덱싱되지 않음)를 검색하는 데 약 8 분이 소요됩니다. 문제는 로컬 및 내 온라인 준비 서버에서 동일합니다. 그것은 8 분 동안 일시 정지 후이 쿼리를 생성 :

select candidate0_.CandidateID as Candidat1_4_, candidate0_.Email as 
Email7_4_, candidate0_.FirstName as FirstNam8_4_, candidate0_.LastName as 
LastNam17_4_, candidate0_.Zip as Zip30_4_ from Candidate.Candidates 
candidate0_where exists (select 1 from Candidate.CandidateFields fields1_ 
where candidate0_.CandidateID=fields1_.CandidateID and fields1_.Name=?) 
binding parameter [1] as [VARCHAR] - [Accounting] 

편집 : (가) 자동 생성 된 쿼리에 EXISTS 절에서 문제가 확실히 유래한다. 이제 왜 그렇게하는지, 더 효율적인 쿼리를 생성하는 방법을 살펴보아야합니다.

이상한 부분은 매개 변수없이 간단한 findAll()을 수행하면 실제로 선택 및 구문 분석하는 것입니다. 결과보다는 일시 중지. 이름보다는 ID로 검색하면 문제가 지속됩니다.

EXPLAIN SELECT * 
FROM Candidates 
INNER JOIN Candidate.CandidateFields 
WHERE CandidateFields.CandidateID = Candidates.CandidateID AND 
CandidateFields.Name = "Accounting"; 

결과 :

<table> 
 
<tr> 
 
    <th>id</th> 
 
    <th>select_type</th> 
 
    <th>table</th> 
 
    <th>partitions</th> 
 
    <th>type</th> 
 
    <th>possible_keys</th> 
 
    <th>key</th> 
 
    <th>key_len</th> 
 
    <th>ref</th> 
 
    <th>rows</th> 
 
    <th>filtered</th> 
 
    <th>extra</th> 
 
</tr> 
 
    <tr> 
 
    <td>1</td> 
 
    <td>SIMPLE</td> 
 
    <td>CandidateFields</td> 
 
    <td>null</td> 
 
    <td>ALL</td> 
 
    <td>null</td> 
 
    <td>null</td> 
 
    <td>null</td> 
 
    <td>null</td> 
 
    <td>30601</td> 
 
    <td>10</td> 
 
    <td>Using where</td> 
 
    </tr> 
 
    <tr> 
 
    <td>1</td> 
 
    <td>SIMPLE</td> 
 
    <td>Candidates</td> 
 
    <td>null</td> 
 
    <td>eq_ref</td> 
 
    <td>PRIMARY</td> 
 
    <td>PRIMARY</td> 
 
    <td>4</td> 
 
    <td>Candidate.CandidateFields.CandidateID</td> 
 
    <td>1</td> 
 
    <td>100</td> 
 
    <td>Using where</td> 
 
    </tr> 
 
    
 
    </table>
~ 1 초 내 DB 관리 도구 결과를 반환의 실제 SQL 쿼리를 실행

(여기는 요청에 따라 EXPLAIN 결과 쿼리입니다)

편집 : 문제는 확실히 자동 생성 된 쿼리의 EXISTS 절에서 유래합니다. 이제 왜 그렇게하는지, 더 효율적인 쿼리를 생성하는 방법을 살펴보아야합니다.

모든 사항과 모든 도움을 주시면 감사하겠습니다. 필요한 경우 명확히 할 수 있습니다. 건배!

+0

안녕하세요, 이름이 색인 생성되지 않았습니다. 그것은 30k 레코드로 쿼리 속도에 상당한 영향을 미칩니 까?더 자세히 설명해야 할 경우 알려 주시기 바랍니다 –

+0

아마도 "DB 관리 도구"에 EXPLAIN 접두어가 붙은 요청을 입력하고 질문에 결과를 게시하면 CandidateFields의 색인 (CandidateID, Name)이 문제의 해결책이 될 수 있습니다. –

+1

생성 된 쿼리에서'WHERE EXISTS (SELECT 1 FROM correlated subquery) '때문에 오랜 시간이 걸립니다. MySQL은 일반적으로 상관 하위 쿼리를 잘 처리하지 않습니다. 내가 이것에 대해 무엇을해야하는지 알았다면 나는 대답을 썼을 것이다. –

답변

0

더 필드는

왜 인덱싱되지 않습니다? 후자는 반 조인 (EXISTS() 하위 쿼리)에 대한 커버링 인덱스되기 때문에

CREATE INDEX i2 ON Candidate.CandidateFields(Name, CandidateID); 

:

CREATE INDEX i1 ON Candidate.CandidateFields(Name); 

또는 더 빨리이 특정 쿼리에 대한 : 그냥 여기이 인덱스를 추가 할 수 있습니다.