簡體   English   中英

使用 mysql 的搜索查詢的性能問題

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM