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行をプルする方が効率的かもしれません。 'timestamp'が一意であることが保証されている場合、そのようなクエリを作成することは可能ですが、クエリテキストは現在のものよりもかなり複雑になります。各期間内に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つの非常に厄介で複雑な方法は、インラインビューを使用して、次のような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)
そして、各期間のMAX(作成済み)を引き戻します。GROUPBY p.period_end、それをインラインビューでラップします。
そして、それをテーブルに結合して、各行を取得します。
しかし、それは本当に、本当に厄介で、理解するのが難しく、あなたがすでに行っていることよりも速く(またはより効率的に)なる可能性はありません。最も改善できるのは、9つのクエリを実行するのにかかる時間です。