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 つのテーブルがあり、各リスト ID (そのうち 1,000 から 10,000 まで) に対してテーブルごとに個別の SELECT クエリを実行します。したがって、私の 1 つの JPA クエリは、約 7,000 クエリのように見えます!

4

2 に答える 2

0

以下は、問題のデバッグに関する個人的な考えです。

  • mysqlクエリログをオンにして、JPAが各listingIdのすべてのクエリにMySQLにアクセスしないことを確認します。

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

  • パフォーマンスの原因がMySQLであるかどうかを確認し、MySQLデータベースで同等のSQLを実行します。

    ListingSetからlistingIdを選択します(実際のlistingIdをここに入力します)。

    ListingId列にインデックスがあることを確認してください(インデックスがすでに存在している可能性が非常に高いです)

  • MySQLから行を読み取るだけなので、より多くのスレーブ用にReplicateをセットアップしてから、ListingIdをすべてのスレーブMySQLに分割し、後で結果をマージすることができます。 http://dev.mysql.com/doc/refman/5.0/en/replication-howto.html

于 2012-12-07T13:57:00.010 に答える
0

この問題は、JPA の使用が原因でした。私のエンティティには多くの関係があったため、1 つのクエリが 1,000 ~ 10,000 のクエリに爆発しました。

解決策は、JPA でバッチ処理を使用して、ORM n + 1 クエリの問題を防ぐことです。バッチ処理により、JPA はエンティティごとに 1 回ではなく、関連するテーブルから関連するすべての行を一度に要求します。このソリューションは、クエリが多くの結果を返し、クエリ対象のエンティティに多くの関係がある場合に適しています。

JPA の潜在的な問題を判断する最も簡単な方法は、より詳細なログを有効にすることです。EclipseLink の場合、次のプロパティを追加しますpersistence.xml

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

EclipseLink のデフォルト設定で生成されるロギングには、JPQL 形式のクエリのみが表示されることに注意してください。

于 2012-12-07T20:49:33.920 に答える