3

我有一个由 Solr 索引的 MySQL 数据库。我使用 Solr(快速)执行搜索,并使用 JPA 从数据库中检索 Solr 搜索中的每个结果。JPA 在WHERE IN非常慢的数据库上运行查询。

有没有办法让这个过程更快,或者重构设计以提高性能?

我刚刚将整个应用程序从使用 MySQL 的全文搜索重构为使用 Solr,现在性能更差了。

注意:我需要立即对所有结果进行计算,因此我不能使用分页。

Java代码:

    SolrDocumentList documentList = response.getResults();
    Collection<String> listingIds = new ArrayList<>();
    for(SolrDocument doc : documentList) {
        String listingId = (String) doc.getFirstValue("ListingId");
        listingIds.add(listingId);
    }

    Query query = em.createNamedQuery("getAllListingsWithId");
    query.setParameter("listingIds", listingIds);
    List<ListedItemDetail> listings = query.getResultList();

命名查询:

<query>Select listing from ListingSet listing where listing.listingId in :listingIds</query>

附加信息:

SHOW CREATE TABLE ListingSet产生[缩短]:

CREATE TABLE `listingset` (
  `LISTINGID` int(11) NOT NULL,
  `STARTDATE` datetime DEFAULT NULL,
  `STARTPRICE` decimal(10,2) DEFAULT NULL,
  `TITLE` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`LISTINGID`),
  KEY `FK_LISTINGSET_MEMBER_MEMBERID` (`MEMBER_MEMBERID`),
  CONSTRAINT `FK_LISTINGSET_MEMBER_MEMBERID` FOREIGN KEY (`MEMBER_MEMBERID`) REFERENCES `member` (`MEMBERID`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1

调查生成的 SQL

查看生成的 SQL,JPA 会针对单个 JPA 查询运行大量 SQL 查询。ListingSet 表有 7 个与之链接的表,并为每个表运行一个单独的 SELECT 查询以获取每个列表 ID(其中有 1,000 - 10,000 个)。所以我的一个 JPA 查询被炸成了大约 7,000 个查询!

4

2 回答 2

0

以下只是关于调试问题的个人想法:

  • 打开 mysql 查询日志并检查 JPA 不访问 MySQL 每个 ListingId 的每个查询。

    mysql -uroot -pYOUR-PASSWORD -e "SET GLOBAL log_output = 'FILE';设置 GLOBAL general_log_file = '/tmp/mysql.log';SET GLOBAL general_log = 'ON';" 尾 -f /tmp/mysql.log

  • 检查性能是否是由 MySQL 引起的,在您的 MySQL 数据库中运行等效的 SQL。

    从 ListingSet 中选择列表,其中列表 ID 位于(将您的真实列表 ID 放在这里);

    确保在 ListingId 列上有索引(也许很有可能索引已经存在)

  • 由于您只从 MySQL 读取行,也许您可​​以为更多从属设置 Replicate,然后将您的 ListingIds 拆分到所有从属 MySQL,然后合并结果。 http://dev.mysql.com/doc/refman/5.0/en/replication-howto.html

于 2012-12-07T13:57:00.010 回答
0

该问题是由我使用 JPA 引起的。由于我的实体有很多关系,单个查询会爆炸成 1,000-10,000 个查询。

解决方法是在 JPA 中使用Batch Processing来防止 ORM n+1 查询问题。批处理导致 JPA 一次从相关表中请求所有相关行,而不是为每个实体一次请求。当一个查询返回很多结果,并且被查询的实体有很多关系时,这种解决方案是合适的。

确定 JPA 潜在问题的最简单方法是启用更精细的日志记录。对于 EclipseLink,将属性添加到persistence.xml

  <property name="eclipselink.logging.level" value="FINEST"/>

请注意,在 EclipseLink 的默认设置下生成的日志记录仅显示查询的 JPQL 形式。

于 2012-12-07T20:49:33.920 回答