[英]Performance issue on search query using mysql
我在具有 250000 多條記錄的表上進行多個連接的搜索查詢出現性能問題。 我實現的最佳時間是 1.5 秒,默認分頁和排序由 JPA 提供。此外,我嘗試在列上添加索引,但由於連接,時間保持不變。 有什么辦法可以提高查詢的性能嗎?
"select new com.app.e_library.service.dto.BookDto(book.id,book.isbn," +
" book.title, book.publicationYear, book.pageCount, genre.name," +
" book.bookStatus, publisher.publisherName, author.name) " +
"from BookEntity book " +
"inner join book.bookGenre genre " +
"inner join book.publisher publisher " +
"inner join book.author author " +
"where book.isbn like :key% or " +
"book.title like :key% or " +
"trim(book.publicationYear) like :key% or " +
"genre.name like :key% or " +
"publisher.publisherName like :key% or " +
"author.name like :key%"
查詢由 hibernate 生成。
Hibernate:
select
bookentity0_.id as col_0_0_,
bookentity0_.isbn as col_1_0_,
bookentity0_.title as col_2_0_,
bookentity0_.publication_year as col_3_0_,
bookentity0_.page_count as col_4_0_,
bookgenree1_.name as col_5_0_,
bookentity0_.book_status as col_6_0_,
publishere2_.name as col_7_0_,
authorenti3_.name as col_8_0_
from
book bookentity0_
inner join
book_genre bookgenree1_
on bookentity0_.genre_id=bookgenree1_.id
inner join
publisher publishere2_
on bookentity0_.publisher_id=publishere2_.id
inner join
author authorenti3_
on bookentity0_.author_id=authorenti3_.id
where
bookentity0_.isbn like ?
or bookentity0_.title like ?
or trim(bookentity0_.publication_year) like ?
or bookgenree1_.name like ?
or publishere2_.name like ?
or authorenti3_.name like ?
order by
bookentity0_.id asc limit ?
Hibernate:
select
count(bookentity0_.id) as col_0_0_
from
book bookentity0_
inner join
book_genre bookgenree1_
on bookentity0_.genre_id=bookgenree1_.id
inner join
publisher publishere2_
on bookentity0_.publisher_id=publishere2_.id
inner join
author authorenti3_
on bookentity0_.author_id=authorenti3_.id
where
bookentity0_.isbn like ?
or bookentity0_.title like ?
or trim(bookentity0_.publication_year) like ?
or bookgenree1_.name like ?
or publishere2_.name like ?
or authorenti3_.name like ?
圖書實體
@Entity
@Table(
name = "book",
uniqueConstraints = {
@UniqueConstraint(name = "book_isbn_unique",column Names = "isbn")
},
indexes = {
@Index(name = "isbn_index", columnList = "isbn"),
@Index(name = "title_index", columnList = "title"),
}
)
public class BookEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "isbn", nullable = false)
@NotBlank
private String isbn;
@Column(name = "title", nullable = false)
@NotBlank
private String title;
@Column(name = "publication_year")
@Valid
private short publicationYear;
@Column(name = "page_count")
@Valid
@Range(min = 50, max = 5000)
private int pageCount;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="genre_id",referencedColumnName = "id", nullable=false)
@ToString.Exclude
private BookGenreEntity bookGenre;
@Column(name = "book_status", nullable = false)
@Enumerated(EnumType.STRING)
private BookStatusType bookStatus;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "publisher_id", referencedColumnName = "id", nullable = false)
@NonNull
@ToString.Exclude
private PublisherEntity publisher;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "pick_detail_id", referencedColumnName = "id")
@ToString.Exclude
private PickDetailEntity pickDetail;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", referencedColumnName = "id", nullable = false)
@NonNull
@ToString.Exclude
private AuthorEntity author;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "book_image_id", referencedColumnName = "id")
@ToString.Exclude
private BookImageEntity bookImage;
圖書類型實體
@Entity
@Table(
name = "book_genre",
uniqueConstraints = {
@UniqueConstraint(name = "book_genre_name_unique", columnNames = "name")
},
indexes = {
@Index(name = "name_index", columnList = "name"),
}
)
public class BookGenreEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name", nullable = false)
@NotBlank
private String name;
@OneToMany(
targetEntity = BookEntity.class,
mappedBy = "bookGenre",
cascade=CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true)
@ToString.Exclude
private List<BookEntity> books;
出版商實體
@Entity
@Table(
name = "publisher",
uniqueConstraints = {
@UniqueConstraint(name = "publisher_name_unique", columnNames = "name")
},
indexes = {
@Index(name = "name_index", columnList = "name")
}
)
public class PublisherEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false)
@NotBlank
private String publisherName;
@OneToMany(
targetEntity = BookEntity.class,
mappedBy = "publisher",
cascade=CascadeType.ALL,
fetch = FetchType.LAZY)
@ToString.Exclude
private List<BookEntity> books;
作者實體
@Entity
@Table(
name = "author",
uniqueConstraints = {
@UniqueConstraint(name = "author_name_unique", columnNames = "name")
},
indexes = {
@Index(name = "name_index", columnList = "name")
}
)
public class AuthorEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false)
@NotBlank
private String name;
@OneToMany(
targetEntity = BookEntity.class,
mappedBy = "author",
cascade=CascadeType.ALL,
fetch = FetchType.LAZY)
@ToString.Exclude
private List<BookEntity> books;
您不必在@JoinColumn
中指定referencedColumnName
您在BookEntity#isbn
上有一個@UniqueConstraint
,因此無需添加額外的索引。
您需要BookEntity#publication_year
的索引:
indexes = {
@Index(name = "title_index", columnList = "title"),
@Index(name = "publication_year_index", columnList = "publication_year"),
}
你可以試試這個查詢:
@NamedQuery(name="BookEntity.search", query="select book from BookEntity book"
+ " inner join fetch book.genre genre"
+ " inner join fetch book.publisher publisher"
+ " inner join fetch book.author or author"
+ " left join fetch book.pickDetail"
+ " where book.isbn like :key"
+ " or book.title like :key"
+ " or book.publicationYear = :year"
+ " or genre.name like :key"
+ " or publisher.publisherName like :key"
+ " or author.name like :key")
而這個 function:
private EntityManager em;
public List<BookEntity> search(String key, short year) {
return em.createNamedQuery("BookEntity.search", BookEntity.class)
.setParameter("key", key + "%")
.setParameter("year", year)
.getResultList();
}
您是否知道您正在進行敏感案例搜索? 那不是很友好。 此外,用戶無法使用標題中間的詞進行搜索。
為避免這種情況,您必須使用類似的東西:
upper(book.title) like :key
和
setParameter("key", "%" + key.toUpperCase() + "%")
但這將觸發全面掃描。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.