長々とすみません、完全な説明をしたかったのです!別のテーブルからの ID に関する情報を表示するレポートを表示する必要があります。ID に対してテーブルに同じ国エントリを複数回含める方法に注意してください (情報は定期的に複数回クエリされますが、その間に移動していない可能性があるため)、異なる国エントリを持つこともできます (国を変更します)。
データの簡単な説明: 私は以下の表を持っています:
CREATE TABLE IF NOT EXISTS `country` (
`id` mediumint(8) unsigned NOT NULL,
`timestamp` datetime NOT NULL,
`country` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`,`timestamp`),
KEY `country` (`country`),
KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
エントリは次のようになります。
41352 2012-03-26 15:46:01 Jamaica
41352 2012-03-05 22:49:41 Jamaican Applicant
41352 2012-02-26 15:46:01 Jamaica
41352 2012-02-16 12:11:19 Jamaica
41352 2012-02-05 23:00:30 Jamaican Applicant
このテーブルには現在、合計約 214,590 行ありますが、テスト データが実際のデータに置き換えられると、数百万行になります。
私が欲しいのは、y 時間以降に x 国を離れたすべての人に関する情報です。上記のデータで実行されたと仮定して、出力したい方法は次のとおりです。
id name last country TIMESTAMP o_timestamp
41352 Sweet Mercy Jamaica 2012-03-26 15:46:01 2012-03-05 22:49:41
41352 Sweet Mercy Jamaica 2012-02-16 12:11:19 2012-02-05 23:00:30
o_timestamp が特定の日付 (たとえば 100) よりも新しい場合、country は移動先であり、元の国 (表示されていません) はクエリに渡すものです (上記のデータに基づくジャマイカの申請者)。
要件を満たすために次のクエリを作成し、特定の ID を使用してテストしました。
SELECT a.id,
c.name,
c.last,
a.country,
a.timestamp,
b.timestamp AS o_timestamp
FROM country a
INNER JOIN user_info c
ON ( a.id = c.id )
LEFT JOIN country AS b
ON ( a.id = b.id
AND a.timestamp != b.timestamp
AND a.country != b.country )
WHERE b.timestamp = (SELECT c.timestamp
FROM country c
WHERE a.id = c.id
AND a.timestamp > c.timestamp
ORDER BY c.timestamp DESC
LIMIT 1)
AND a.id = 965
私はこれを完了しました (合計 7、クエリは 0.0050 秒かかりました)
そして拡張説明により、次のことが明らかになりました。
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY c const PRIMARY PRIMARY 3 const 1 100.00
1 PRIMARY a ref PRIMARY PRIMARY 3 const 16 100.00
1 PRIMARY b eq_ref PRIMARY,timestamp PRIMARY 11 const,func 1 100.00 Using where
2 DEPENDENT SUBQUERY c index PRIMARY,timestamp timestamp 8 NULL 1 700.00 Using where; Using index
だから私は私がかなり上手だと思って、これに飛び込んだ:
SELECT a.id,
c.name,
c.last,
a.country,
a.timestamp,
b.timestamp AS o_timestamp
FROM country a
INNER JOIN user_info c
ON ( a.id = c.id )
LEFT JOIN country AS b
ON ( a.id = b.id
AND a.timestamp != b.timestamp
AND a.country != b.country )
WHERE b.timestamp = (SELECT c.timestamp
FROM country c
WHERE a.id = c.id
AND a.timestamp > c.timestamp
ORDER BY c.timestamp DESC
LIMIT 1)
AND b.country = "whatever" AND timestamp > DATE_SUB(NOW(), INTERVAL 7 DAY)
このクエリは、200 件のレコードがあり、完了しなかった国で完了するのに驚くべき 6 分 54 秒かかりました (午後と夜に外出し、
データベースに9000件のレコードがある国では、家に帰るので合計約8時間です。実際のデータでは、国は 10000 倍簡単にそこにある可能性があります。100kは不合理ではありません。
だから私は拡張を説明し、これを取得します:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3003 100.00
1 PRIMARY c eq_ref PRIMARY PRIMARY 3 b.id 1 100.00
1 PRIMARY a ref PRIMARY PRIMARY 3 b.id 7 100.00 Using where
3 DEPENDENT SUBQUERY c index PRIMARY,timestamp timestamp 8 NULL 1 700.00 Using where; Using index
2 DERIVED country range country,timestamp country 195 NULL 474 100.00 Using where; Using index
そのため、大きく見えますが、不当ではありません。
[スペースの構成変数を削除しました。必要に応じて、パフォーマンス情報もお知らせください。おそらくクエリの問題です。]
何か見逃した場合はお知らせください。