2016-10-17 4 views
0

私は助けが必要なこのクエリを持っています。そこでと呼ばれるテーブルがあり、複数の日付を持つことができる長い文字フィールドのDELという列があります。特定の日付範囲のフィールドに日付があるたびに1つの行を含む出力テーブルを作成する必要があります。多くのユニオンを使用してMySQLクエリを長時間最適化する方法

select ... where ... DEL like "%my_date%"という単純な理由だけでは、DELの列に複数の日付を含めることができないため、複数の行を出力セットに戻す必要があります。 DELの列。

ソリューション私はそれが作品を思い付いたが、このような非常に遅いルックスです:DELフィールドに特定の日付文字列を含む任意の行(date_format(now() + interval @x day, '%m/%d/%Y'))がある場合

create temporary table jobtrack.ship_helpert3 as 
select * from 
(
    (
    select 
     date_format(now() - interval 3 day, '%m/%d/%Y') as `Ship_Date`, 
     more_columns 
    from 
     jobticket.insertjobticket 
    where   
     DEL like concat('%',date_format(now() - interval 3 day, '%m/%d/%Y'),'%') 
    ) union (
    select 
     date_format(now() + interval 2 day, '%m/%d/%Y') as `Ship_Date`, 
     more_columns 
    from 
     jobticket.insertjobticket 
    where   
     DEL like concat('%',date_format(now() + interval 2 day, '%m/%d/%Y'),'%') 
    ) union (
    select 
     date_format(now() + interval 1 day, '%m/%d/%Y') as `Ship_Date`, 
     more_columns 
    from 
     jobticket.insertjobticket 
    where   
     DEL like concat('%',date_format(now() + interval 1 day, '%m/%d/%Y'),'%') 
    ) union ... 
) t; 

selectクエリをチェックします。クエリはプログラムによって構築され、非常に長い時間がかかることがあります。多くの日付に対してクエリのチェックを行うことができるようにするためです。

insertjobticketテーブルには40K個の行が含まれていますが、そのサイズが拡大しているため、上記のクエリは完了には時間がかかりすぎます。私はいつもunionのすべてが効果的に独自のサブクエリを作成して、各日付ごとに何度も何度もテーブル全体をスキャンする必要があるので、なぜそれほど時間がかかるのか理解しています。私はこの仕事をより効率的にする方法を知りません。

誰でもこのクエリをスピードアップする方法を知っていますか?

助けてくれてありがとう、もっと明確にする必要がある場合はお知らせください。

+1

正直なところ、1つの解決策があります。列を1つの列「DEL」にするのではなく、行ごとに1つの日付を含む新しい表を作成します。アプリケーションを変更できない場合は、トリガーでそれを行い、列を更新するたびに新しいテーブルを更新してください。あなたがやることはパッチワークだけです(基本的に、このクエリを実行するたびにこの新しいテーブルを作成することを意味します)。 – Solarflare

+2

はい。スキーマを正規化します。または、RDBMSを使用しても構いません。 – Strawberry

+0

私はこの提案を完全に理解してくれてありがとう。既存のインフラストラクチャのコンテキストで作業するクライアントの要求に取り組む必要があります。間違いなくそれは理想的ではありません。 –

答えて

1

コメントに既に記載されているように、唯一の正しい解決策はデータを正規化することです。つまり、1つの納品日と1行あたりの主キーがinsertjobticketの新しいテーブルを作成し、列delの代わりに、または列DELが更新されるたびにこの表を更新するトリガーによって少なくとも間接的に更新されます。

次の回避策は、あなたのクエリを改善する必要があり、それを行うことはできませんので:

select 
    del_dates.Ship_Date, 
    othercolumns 
from insertjobticket 
join (
    select concat(date_format(now() + interval 2 day, '%m/%d/%Y')) 
      collate utf8_general_ci as Ship_Date 
    union select concat(date_format(now() + interval 1 day, '%m/%d/%Y')) 
    union select concat(date_format(now() + interval -15 day, '%m/%d/%Y')) 
    ... 
) del_dates 
on insertjobticket.del like concat('%', del_dates.Ship_Date, '%'); 

(もしあれば、あなたのテーブルに使用するか、どちらを見て、それを離れて去る1にあなたを照合順序を変更必要)。

これは、クエリを実行するたびに必要な正規化手順(要求された日付)を基本的に実行し、インデックスを使用できなくなります。 explainの出力がinsertjobticketではなく、派生テーブルに対してusing join bufferと表示されていることを確認してください。そうでない場合はjoinstraight_joinに置き換えてください。

40k行の場合、これは大きな問題ではないかもしれません。とにかく、実際の正規化を除いて他の方法はありません。クエリは行の量に比例して減速することに注意してください(40k行は40kと約10倍の時間がかかります)。エフェクトインデックスによって回避できます。したがって、現在(または時には)遅すぎる場合、最終的には正規化する必要があります(または、この回避策で作成された問題の回避策として、古いエントリをマークして結合条件で除外する列を追加する必要があります)。

Btwでは、コードをプログラムで生成するので、日付のリストを作成するのに問題はありません。そうでなければ、別のサブクエリを使用して一般的な日付のリストを生成し、特定の範囲のものを選択することができます。

+0

これはすばらしい答えです。回避策問合せをいただきありがとうございます。私はそれを少し速くするかどうかを試してみます。 DELカラムを独自のテーブルに入れて、 "正しい"方法で何を言っているのか理解しています。 varcharの代わりに日付フィールドを使用する。しかし、私はあなたがインデックスについての底に向かって何を指しているのかはよく分かりません。クエリを高速化するためにインデックスを使用するにはどうすればよいですか? –

+1

@jeffery_the_wind索引はデータベースの重要な部分であり、説明の範囲を超えて説明しています。あなたは本当にそれを読むべきです。要約すると、ニックネーム(「日付」)で電話帳の電話番号を検索する方法をイメージします。あなたはそれを最初から最後まで読まない - それが注文されているので、結果はずっと速く(そしてエントリーの総数からほぼ独立して)見つけることができる。しかし、2つのニックネームを書くと、あなたの妻と子どもたち(「第2、第3、第4配信日」)が隣り合っていると、電話番号を見つけるのが難しくなります。基本的にデータベース設計です。 – Solarflare

+0

ありがとう、そのコメントでも良い説明。 –

1

データベースを使用する際には、格納されたデータの最終的な使用を考慮する必要があります。

この場合、格納しようとしていたとおりにDELを解析し、日付ペア(DELに埋め込まれています)とID(insertjobticket)の別のテーブルを作成する必要がありました。

事実の後に解析を行おうとすると、処理がはるかに遅くなり、スケーリングの問題が発生します。

関連する問題