[英]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.