TL; DR
選択した回答のクエリは「機能するはずです」。些細なセットでもパフォーマンスは良好です。しかし、大きなセットでは、それは素晴らしいパフォーマンスになるでしょう。
最高のパフォーマンスを得るには、範囲条件で裸の列を参照するクエリを使用します。このようなもの:
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players`
WHERE `lastlogin` > 0
AND `lastlogin` < UNIX_TIMESTAMP('2012-10-01 00:00:00')
元の回答
(クエリ内の)列エイリアスlast
は、(クエリ内の)WHERE句で参照できません。これはMySQLの構文規則です。(基本的に、このルールの理由は、WHERE句の述語が処理されるときに、そのエイリアスによって参照される式が使用できないためです。)
HAVING
ただし、その列エイリアスは、句の述語で参照できます。句は、実行プランのHAVING
ほぼ最後に処理されます。これは機能しますが、パフォーマンスの観点から問題があります。
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players` WHERE `lastlogin` <> 0
HAVING `last` < '2012-10-01 00:00:00';
その実行プランは、インラインビューを使用して(派生テーブルを作成するため)、派生テーブルに対してSELECTを実行するのとほぼ同じです(これはパフォーマンスの観点からも問題があります)。
SELECT d.*
FROM (
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players` WHERE `lastlogin` <> 0
) d
WHERE `last` < '2012-10-01 00:00:00';
last
内部クエリ(dとしてエイリアスされたインラインビュー)が最初に実行され、結果セットがMyISAMテーブルとして保存されるため、ここで列エイリアスを参照できます。次に、外部クエリがMyISAMテーブルに対して実行されます。また、このクエリでは、last
はテーブルから列名を参照しているため、WHERE句で参照できます。
重要な注意点:
そういうわけであなたが尋ねた質問に答えます。だが、
あなたは本当にそれをしたくありません!
このクエリは基本的にテーブルのコピーを作成し、そのコピーに対してクエリを実行するため、このアプローチでは大きなセットに対して問題のあるパフォーマンスが見られます。そのfrom_unixtime関数は、テーブル内のすべての行に対して実行されます(lastloginがNULLまたはゼロに等しい行を除く)。
パフォーマンスの観点からは、単一のクエリ(インラインビューなし)を使用し、WHERE句の裸の列に述語を使用する方がはるかに優れています。
理想的にlastlogin
は、DATETIMEまたはTIMESTAMPデータ型として格納されます。ただし、その列が整数である場合は、述語のリテラル定数を整数に変換してから、それを裸の列と比較する方がはるかに優れています(パフォーマンスの面で)。これにより、MySQLは、リテラルと比較するために、すべての行で関数をlastlogin
実行するのではなく、少なくとも先頭の列としてあるインデックスで範囲スキャンを実行することを検討できます。from_unixtime
UNIX_TIMESTAMP()
MySQLは、DATETIMEを整数値に変換するための便利な関数を提供します(これは基本的にFROM_UNIXTIME()
関数の逆ですが、いくつかの注意点があります。
最高のパフォーマンスを得るには、次の形式のクエリが必要です。
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players`
WHERE `lastlogin` <> 0
AND `lastlogin` < UNIX_TIMESTAMP('2012-10-01 00:00:00')