1

約100万件のレコード「連絡先」を持つユーザーのテーブルがあります。また、送信したメールのログを別のテーブル「log_sent」に保存します。これも約 100 万レコードです。

ニュースレターをまだ受け取っていないユーザーを見つける必要があります。したがって、次のクエリを使用して、送信する必要がある次のユーザーを取得しています。

SELECT contact.* 
FROM contacts AS contact
LEFT JOIN log_sent AS sent ON sent.contact_id = contact.id
WHERE sent.id IS NULL 
LIMIT 0 , 1

これは、EXPLAIN クエリが返すものです。

id | select_type | table   | type | possible_keys | key        | key_len | ref                        | rows    | Extra
  1 | SIMPLE      | contact | ALL  | NULL          | NULL       | NULL    | NULL                       | 1031628 | 
1 | SIMPLE      | sent    | ref  | contact_id    | contact_id | 4       | admin_marketing.contact.id | 1       | Using where; Not exists

log_sent テーブルにcontact_idインデックスが作成されました。連絡先テーブルにはidプライマリ インデックスとして.

このクエリの実行には約1.8数秒かかります。また、log_sent テーブルが大きくなっているため、これが問題になります。このクエリを最適化するにはどうすればよいですか。

私が理解していることは、クエリが連絡先テーブルの100万件すべてのレコードを検索しているようです。しかし、使用するユーザー数を制限するために使用できるインデックスは実際にはありません。または多分私は何かを逃していますか?

4

2 に答える 2

1

本当に1 つの行だけが必要な場合は、not exists句を使用するようにクエリを書き直すと、違いが生じる可能性があります。

SELECT contact.* 
FROM contacts AS contact
WHERE NOT EXISTS ( SELECT 1 FROM log_sent AS sent WHERE sent.contact_id = contact.id )
LIMIT 1

そうでない場合は、論理を逆にすることをお勧めします。「送信」テーブルを作成し、メールを送信する必要があるときに入力します。新しいメールを送信するときに、そこから削除 (およびログ テーブルに追加) します。

于 2013-06-09T08:06:52.747 に答える
0

異なる時期に異なるニュースレターを送信するため、これは機能しません。そのため、これから行うキャンペーンごとに新しいフィールドを追加する必要があります

次に、@Denisが提案したことを好きにしてください。異なるニュースレターごとに新しいテーブルを作成する必要はありません。モックアップ スキーマは次のとおりです。

連絡先 (contact_id, ...)
ニュースレター キャンペーン (キャンペーン ID、キャンペーン名)
ニュースレターの送信 (campaign_id、contact_id)
ニュースレター ログ (campaign_id、contact_id、send_date)

新しいキャンペーンを作成

  • 単一のクエリですべての連絡先を Newsletter_sending に挿入します。
  • INSERT INTO newsletter_sending SELECT {$new_campaign_id}, contact_id FROM contacts;.

連絡先にニュースレターを送信する

  • Newsletter_sending リストから連絡先を削除し、ログに追加します
  • DELETE FROM newsletter_sending WHERE campaign_id = {$campaign_id} AND contact_id = {$contact_id}
  • INSERT INTO newsletter_log VALUES({$campaign_id, {$contact_id}, NOW())

ニュースレターを受け取っていないユーザーに問い合わせる

  • SELECT * FROM newsletter_sending WHERE campaign_id = {$campaign_id}

ニュースレターを受け取ったユーザーに問い合わせる

  • SELECT * FROM newsletter_log WHERE campaign_id = {$campaign_id}

私があなたに変更を強く勧める理由は、現在のスキーマが拡張できないからです。連絡先とログがどんどん大きくなると、どんどん遅くなっていきます

于 2013-06-09T07:32:54.260 に答える