2017-12-28 9 views
0

私は次のクエリを最適化することを任されています。`from_unixtime`はこのクエリを遅くすることができますか?

select 
c.account_key, 
c.cohort, 
date(concat(year(from_unixtime(min(f.processdate_est_key))), '-', 
month(from_unixtime(min(f.processdate_est_key))), '-1')) as 
customer_conversion_month 
from 
bidw_stage.cohort c left join 
bidw.fact f 
on 
c.account_key = f.account_key and 
f.usage_dollars != 0 and 
12 * (year(from_unixtime(f.processdate_est_key)) - year(c.cohort)) + 
(month(from_unixtime(f.processdate_est_key)) - month(c.cohort)) >= 2 
group by c.account_key, c.cohort; 

昨年1月に完了するまでに30秒かかりました。今はほぼ3分かかります。ファクトテーブルには約3,000万レコードが含まれ、コホートテーブルは約20kです。ファクト表属性 'account_key'は索引付けされていますが、「コホート」表にはありません。

私はこのクエリを記述していないと、これは、クエリを遅くすることでしたオリジナルのコーダは、この

12 * (year(from_unixtime(f.processdate_est_key)) - year(c.cohort)) + 
    (month(from_unixtime(f.processdate_est_key)) - month(c.cohort)) 

理由について何らの文書を残していませんか?どのようにこれを最適化できますか?

+1

カラムで関数を使用すると、インデックスを決して使用できません。インデックスは生の(操作されていない)カラムデータにのみ適用されます –

+0

計算カラムにWHEREがあるものは通常テーブルスキャンが必要なので、性能は残酷になります。これらの列をネイティブの 'DATETIME'形式に切り替えることができれば、半分になります。これらの値の代わりに['DATE_SUB()'](https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-sub)を使用することができますこの式。 – tadman

+0

参考までに、 'processdate_est_key'が少なくとも' cohort'の後の2ヶ月目にあるかどうかチェックします。したがって、 'cohort'が2017年2月にあった場合、2017年4月以降の' processdate_est_key'に当てはまります。 – Barmar

答えて

0

索引付けされた列で関数をコールすると、索引は役立ちません。索引付けされた列の変更されていない値と何かを比較する条件を記述する必要があります。

processdate_est_keyは少なくともcohortの後の2か月後です。この列を日付に変換するのではなく、その年と月を抽出する代わりに、その月の初めにUNIXのタイムスタンプを生成して比較する必要があります。

AND f.processdate_est_key >= 
     UNIX_TIMESTAMP(CONCAT(YEAR(c.cohort + INTERVAL 2 MONTH), 
           MONTH(c.cohort + INTERVAL 2 MONTH), '01')) 

連結は、2ヶ月c.cohort後の日付を取得し、その年と月を抽出し、その月の最初の日を参照し01を追加します。それからf.processdate_est_keyとの比較のためにそれを数値形式に変換するためにUNIX_TIMESTAMPを呼び出します。

+0

それは意味をなさない!ありがとうございました。あまりにも悪い私はあなたを投票することはできません(十分なrepポイントではない)。 –

+0

答えを受け入れることは、アップフォートよりも優れています。 – Barmar

関連する問題