先頭列が のインデックスがある場合created
、MySQL はリバース スキャンを実行できる場合があります。イベントのない 24 時間の期間がある場合、その期間以外の行を返す可能性があります。created
その期間に行を取得していることを確認するには、次のように、列にも下限を含める必要があります。
SELECT * FROM `eventos`
WHERE ...
AND `created` < FROM_UNIXTIME( {$timestamp} )
AND `created` >= DATE_ADD(FROM_UNIXTIME( {$timestamp} ),INTERVAL -24 HOUR)
ORDER BY `created` DESC
LIMIT 1
ここでのパフォーマンスの大きな鍵はcreated
、WHERE 句で参照される他のすべて (またはほとんど) の列と共に、先頭の列としてインデックスを使用し、インデックスがクエリで使用されていることを確認することだと思います。
秒単位まで異なる時間間隔が必要な場合、このアプローチは簡単に一般化できます。
SELECT * FROM `eventos`
WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL 0*{$nsecs} SECOND)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*{$nsecs} SECOND)
ORDER BY `created` DESC
LIMIT 1
コードから、24 時間の期間が任意の時間に制限されているように見えます...時間関数がたとえば 1341580800 ('2012-07-06 13:20') を返す場合、10 の期間はすべて 13 からになります。当日20時~翌日13時20分。
(注: パラメータが UNIX タイムスタンプ整数である場合、これがデータベースによって正しく解釈されていることを確認してください。)
1 回のクエリで 10 行を取得する方が効率的かもしれません。「タイムスタンプ」が一意であることが保証されている場合、そのようなクエリを作成することは可能ですが、クエリ テキストは現在のものよりもかなり複雑になります。各期間内に MAX(timestamp_) を取得し、それを元に戻して行を取得することを台無しにすることはできますが、それは非常に面倒です。
10 行すべてを取得しようとする場合はUNION ALL
、あまりきれいではないアプローチを試してみますが、少なくとも調整は可能です。
SELECT p0.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL 0*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p0
UNION ALL
SELECT p1.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p1
UNION ALL
SELECT p2.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -3*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p2
UNION ALL
SELECT p3.*
FROM ...
繰り返しますが、これは一般化して、引数として秒数を渡すことができます。HOUR を SECOND に置き換え、'24' を秒数を持つバインド パラメータに置き換えます。
かなり長くなりましたが、問題なく動作するはずです。
これを 1 つの結果セットに戻すもう 1 つの非常に面倒で複雑な方法は、インライン ビューを使用して 10 期間の終了タイムスタンプを取得することです。次のようになります。
SELECT p.period_end
FROM (SELECT DATE_ADD(t.t_,INTERVAL -1 * i.i_* {$nsecs} SECOND) AS period_end
FROM (SELECT FROM_UNIXTIME( {$timestamp} ) AS t_) t
JOIN (SELECT 0 AS i_
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
) i
) p
そして、それをテーブルに結合します...
ON `created` < p.period_end
AND `created` >= DATE_ADD(p.period_end,INTERVAL -1 * {$nsecs} SECOND)
そして各期間 GROUP BY p.period_end の MAX(created) を引き戻し、それをインライン ビューでラップします。
そして、それをテーブルに結合して各行を取得します。
しかし、これは非常に厄介で、理解するのが難しく、既に行っていることよりも速く (またはより効率的に) なる可能性はほとんどありません。改善できる最大の改善点は、9 つのクエリを実行するのにかかる時間です。