1

複合キー テーブル CUSTOMER_PRODUCT_XREF があります

__________________________________________________________________
|CUSTOMER_ID (PK NN VARCHAR(191)) | PRODUCT_ID(PK NN VARCHAR(191))|
-------------------------------------------------------------------

私のバッチ プログラムでは、更新された 500 人の顧客を選択し、CUSTOMER が購入した PRODUCT_ID をコンマで区切って取得し、SOLR インデックスを更新する必要があります。私のクエリでは、500 人の顧客を選択し、CUSTOMER_PRODUCT_XREF への左結合を行っています。

SELECT 
    customer.*, group_concat(xref.PRODUCT_ID separator ', ')
FROM
    CUSTOMER customer
LEFT JOIN CUSTOMER_PRODUCT_XREF xref ON customer.CUSTOMER_ID=xref.CUSTOMER_ID  
group by customer.CUSTOMER_ID 
LIMIT 500;

編集:クエリを説明

id  select_type table   type    possible_keys   key      key_len    ref     rows    Extra
1   SIMPLE     customer ALL      PRIMARY        NULL     NULL       NULL    74236   Using where; Using temporary; Using filesort
1   SIMPLE      xref    index     NULL          PRIMARY  1532       NULL    121627  Using where; Using index; Using join buffer (Block Nested Loop)

上記のクエリを 20 分実行した後、接続例外が失われました。

次の(サブクエリ)を試してみましたが、結果を得るのに1.7秒かかりましたが、それでも遅いです。

SELECT 
customer.*, (SELECT group_concat(PRODUCT_ID separator ', ') 
     FROM CUSTOMER_PRODUCT_XREF xref 
        WHERE customer.CUSTOMER_ID=xref.CUSTOMER_ID
        GROUP BY customer.CUSTOMER_ID) 
FROM
CUSTOMER customer
LIMIT 500;

編集: EXPLAIN QUERY が生成します

id  select_type          table      type    possible_keys   key    key_len  ref     rows   Extra
1   PRIMARY              customer     ALL       NULL        NULL    NULL    NULL    74236   NULL
2   DEPENDENT SUBQUERY    xref      index        NULL     PRIMARY   1532    NULL    121627 Using where; Using index; Using temporary; Using filesort

質問

CUSTOMER_PRODUCT_XREF にはすでに両方の列が PRIMARY_KEY と NOT_NULL として設定されていますが、クエリがまだ非常に遅いのはなぜですか? 列に主キーがあれば、その列のインデックスを作成するのに十分だと思いました。さらにインデックスを作成する必要がありますか?

データベース情報:

  • ID にはアルファベットを含めることができるため、データベース内のすべての ID は VARCHAR(191) です。
  • utf8mb4_unicode_ci 文字エンコーディングを使用しています
  • SET group_concat_max_len := @@max_allowed_pa​​cket を使用して、各顧客の product_id の最大数を取得しています。各顧客の製品を取得するために複数の個別のクエリを実行する必要がないように、1 つのメインクエリで group_concat を使用することをお勧めします。
4

2 に答える 2

0

CUSTOMER_PRODUCT_XREF テーブルの CUSTOMER_ID だけにインデックスを作成すると、私の質問のクエリの速度が上がりました。

これで、PRODUCT_ID の PRIMARY_KEY_INDEX と CUSTOMER_ID の CUSTOMER_ID CUSTOMER_ID_INDEX の 2 つのインデックスができました。

于 2013-07-07T12:56:24.720 に答える
0

クエリの元のバージョンは、join最初に実行してから、結果のすべてのデータを並べ替えています。フィールドの大きさを考えると、これはおそらくかなり大きいです。

最初に 500 百人の顧客を選択してから結合を実行することで、そのバージョンを「修正」できます。

SELECT c.*, group_concat(xref.PRODUCT_ID separator ', ')
FROM (select c.*
      from CUSTOMER customer c
      order by c.customer_id
      limit 500
     ) c LEFT JOIN
     CUSTOMER_PRODUCT_XREF xref
     ON c.CUSTOMER_ID=xref.CUSTOMER_ID  
group by c.CUSTOMER_ID ;

大きな影響があるかもしれないし、ないかもしれない代替手段は、次のように、サブクエリで顧客ごとに集計を行い、それを結合することです。

SELECT c.*, xref.products
FROM (select c.*
      from CUSTOMER customer c
      order by c.customer_id
      limit 500
     ) c LEFT JOIN
     (select customer_id, group_concat(xref.PRODUCT_ID separator ', ') as products
      from CUSTOMER_PRODUCT_XREF xref
     ) xref
     ON c.CUSTOMER_ID=xref.CUSTOMER_ID;

あなたが発見したことは、MySQL オプティマイザがこの状況 (制限がパフォーマンスに大きな影響を与える場所) を認識しないということです。この場合、他のデータベース エンジンの最適化の方が優れています。

于 2013-07-07T11:45:34.380 に答える