ブログ

  • 【MySQL】複数カラムを基準にソートする方法【GREATEST】

    MySQLを使い並べ替えをする場合に、一つのカラムだけを基準に並べ替えをすると期待通りの結果が出ない場合があります。

    たとえば、ソートの基準となるカラムに0がある場合、並べ替えにより0が先頭または最後にくることなどがあります。

    この場合には、複数カラムを合わせてソートすることで、期待どおりの結果を得ることができます。

    複数カラムを合わせて、どちらか大きい方を基準に並べ替えるには、GREATEST()関数を使います。

    SELECT * FROM tbl ORDER BY GREATEST(price1,price2) ASC

    こうすることにより、price1カラムとprice2カラムのうちの大きい方を参照して並べ替えることができます。

    これに対して、小さい方を参照して並べ替えるには、LEAST()関数を使います。

    SELECT * FROM tbl ORDER BY LEAST(price1,price2) ASC

    (参考)
    http://dev.mysql.com/doc/refman/5.1/ja/comparison-operators.html

    以上です。

  • 【Linux】grepの否定で検索【vオプション】

    grepの否定の覚書です。

    結論から言うと、grepコマンドに、-v オプションをつけてやると否定の検索ができます。

    ことの顛末も書いておきます。

    HTMLでリンクを記述する場合には、パラメーターの繋ぎに使う&を実体参照として、& と記述しなければならない。

    今回は、そのチェックのために、複数ディレクトリに有る500ほどのファイルに存在する&および&を確認しようと思った次第です。

    そこで、まずは、次のコマンドで、&の存在するファイルを確認。

    grep -n '&' */*

    こうしてやると、&を含む行が表示されますが、&のあるすべての行がすべて表示されるので、&が実体参照で正しく記述されているかの確認が困難です。

    そこで、grepのAND検索と否定を利用して絞り込みをしていきます。

    grep '&' */* | grep -vn '&&'

    絞込みは、パイプ(|)を使います。また、否定には、-v オプションを使います。

    こうしてやることで、&&の行を除外して検索できます。

    同様に、次のようにします(実質1行)。

    grep '&' */* | grep -v '&&' | grep -v 'nbsp' |
    grep -v 'amp' | grep -v 'gt' | grep -nv 'lt'

    これで、&&や他の実体参照を除外できます。

    ただし、これだと、&と実体参照が有る場合、&単独のものも表示されないので、他にもgrepをして確認します。

    grep '&' */* | grep -n 'href'

    こうしてやると&がある行で、かつ、リンクを作っているであろう行を絞り込み検索できます。

    その他、いろいろ試してみて、リンク文字列に、&が単独で利用されていないか確認します。

    もっとスマートなやり方もあると思いますが、急ぎの確認でざっと見るのにはこれで十分でした。

    他のやり方があれば、コメントくださるとありがたいです。

    なお、最初は、grepと正規表現での否定の検索を考えましたが、-v オプションの方が簡単だと思います。正規表現は難しい・・・。

  • MySQLが遅い場合の対策法

    運営サイトのあるページの表示時間が遅くなったので、原因を調べてみるとデータベースのMySQLが原因であるようなので対策をしてみました。

    ■ 現状分析

    サイト公開当初は、サイトのページの表示時間に問題はなかったが、MySQLのあるテーブルのレコード数が20万件を超えたあたりから、表示が遅くなり始める。

    開発環境のXAMPPで確認してみると、なんと10秒前後も表示に時間がかかっており明らかにおかしい。

    実際の運用サーバーでも、表示に1秒前後かかっており、こちらも以前と比べてだいぶ遅くなっている。

    ■ MySQLの速度を改善するための対策

    これまで、MySQLの速度の改善をしたことがないので、まずはネットを検索して情報収集。すると、3点ほど役立ちそうな改善策を発見。

    1. テーブルにインデックス(index)を作成

    2. インデックスを作成したら、WHERE条件句の最初にインデックスを張ったカラムを記述

    3. SQL文の要素をバッククオートやクオートで適切にくくる

    ■ 対策した結果

    上記の3つの対策をすべて試してみましたが、結論からいうと、上記1.に従い、とりあえず適切なカラムにインデックスを作成するだけで、速度が約10倍速くなりました。

    つまり、開発環境のXAMPPでは、表示に約1秒、実運用サーバーでは、約0.1秒ほどに改善しました。なお、実運用サーバーではキャッシュが効いているようで、実際には、0.025秒ほどになってます。

    ■ 上記1. の方法について

    インデックスの作成は、簡単です。phpMyAdminからは、テーブルの構造を表示して、インデックスを作成したいカラムの所定の場所にある、「インデックスを追加」をクリックすることで作成できます。

    また、コマンドを使ってもクリエイト・インデックス構文などを使えば作成できるようです。

    ポイントは、インデックスを作成するカラムを適切に選択すること。検索条件に使用するカラムであり、インデックスによる効果が高いカラムを選択します。

    デメリットとしては、インデックスを作成するとその分だけ容量が増えてしまうことがあります。これは速度とトレードオフなので仕方ないです。約20万件のレコードで20mbあったものが、インデックスを作成したことで、約5mb増えて25mbほどになりました。

    ■ 上記2. の方法について

    インデックスを作成したあと、当該テーブルを検索するSQLも見直しました。ネット上では、インデックスを作成したカラムを、条件句であるWHEREの最初に置くとインデックスが効き速度が上がる旨の記述を何回か見かけたので、そのようにしてみました。

    ただ、この点については、それほど変化はないように思います。インデックスを作成した時点で約10倍速くなったので、この点はあまり関係がないのかもしれません。

    ただ、SQLを書き換えても多少面倒なだけで、それほどデメリットはないので、WHERE句の最初にインデックスのカラムがくるように書き換えておきました。

    ■ 上記3. の方法について

    これは、SQL文を適切なバッククオート、及び、クオートでくくるとSQL文の構文解析にかかる時間が短縮され検索速度があがるというものでしたが、試してみてもそれほど効果は感じられませんでした。

    テーブル固有の値はバッククオートでくくり、ユーザー入力値等はクオートでくくるという書式であり、phpMyAdmin上でSQLを実行すると表示されるSQLの書式です。

    この方法については、あえて採用しませんでした。理由は、書式がMySQLに固有の場合である可能性があること。他のサイトでは、この書式だと、SQLite等でエラーが出る旨の記述がありました。万一後から書き直すことになると面倒なので、この点は現状維持にしておきました。

    ■ 結論

    とりあえず、インデックスを作成することで、速度が改善したので改善策は一応成功したといえます。

    ただ、レコードが増えていくにつれて、適切に対策を講じないと、また遅くなる可能性があるので、5万件か10万件レコードが増えるたびに速度の確認をした方が良さそうです。

    なお、インデックスは、一つのカラムだけでなく、複数のカラムにも作成できるので、次回確認時に速度が遅くなっていたら、別のカラムにもインデックスを作成したいと思います。今回は、一つのカラムにインデックスを作成したことで、満足できる結果なので一つのインデックスのみにしておきました。

    以上です。

  • 【ie】サブドメインとセッション・クッキーの不具合【PHP】

    サブドメインとセッション・クッキーの不具合についての覚書です。

    前日深夜から本日昼過ぎまで、はまってしまいました。

    【問題点】
    メインのドメインとサブドメインでセッション・クッキーの挙動がおかしくなる。それも、インターネット・エクスプローラー(ie9)のみで。

    具体的には、会員サイトにおいて、メインのドメインではログインができるが、サブドメインではログインができなくなるという不具合。

    【原因】
    調べてみると、原因は、インターネット・エクスプローラー(ie)等のいくつかのブラウザで、メインドメインのクッキーと、サブドメインのクッキーを、区別せずに、両方受け入れてしまうことによる不具合と判明。

    【具体例】

    ■ example.com・・・server1で運用
    ■ sub.example.com・・・server2で運用

    この状態でメイン・サブのドメインを運用する場合、本来は、次のようなセッション・クッキーのやりとりに限定されるものです。

    //正常時
    ■ example.com
    ・・・PHPSESSID=abcccccccccc
    ■ sub.example.com
    ・・・PHPSESSID=xyzzzzzzzzzz

    セッション・クッキーが、きちんと分かれています。

    ところが、インターネット・エクスプローラー(ie)だと、サブドメインにおいて、メインのものとサブのもの両方のクッキーがやりとりされてしまいます。

    //異常時
    ■ example.com
    ・・・PHPSESSID=abcccccccccc
    ■ sub.example.com
    ・・・PHPSESSID=xyzzzzzzzzzz
    ・・・PHPSESSID=abcccccccccc

    なぜか、サブドメインにおいて、メインのセッションクッキーのやりとりもされてしまってます。

    このため、メインドメインとサブドメインとの間で、クッキーの値の上書き等が行われ、本来あるべきセッションファイルとセッションクッキーの不一致が生じ、会員サイトなどでは、ログインが不可能となるのです。

    【対策】
    この不具合の症状を回避するための一つの方策としては、セッション名を変更する方法が考えられます。

    ■ example.com
    ・・・PHPSESSID=abcccccccccc
    ■ sub.example.com
    ・・・SUBSESSID=xyzzzzzzzzzz

    上記のように、サブドメインのセッション名をメインのものとは異なるものに設定してやります。

    具体的なコーディングとしては、PHPの場合、session_name関数を利用します。

    http://www.php.net/manual/ja/function.session-name.php

    サブドメインのサイトにおいて、次のようにしてやります。

    session_name("SUBSESSID");

    たったこれだけで、セッション名を変更することができます。

    メインのセッション名は、デフォルトでは、PHPSESSIDなので、こうしてやることで、セッション名の衝突を回避することができます。

    なお、セッション名を変更しても、サブドメインにおいて、メインのセッション・クッキーがやりとりされてしまっていることに変わりがないことには注意が必要です。

    以上です。

  • 【CORESERVER】<Directory>ディレクティブが使えない件

    CORESERVERでは、httpd.conf の代わりに、.htaccessにより、Apacheの挙動を制御することができます。

    しかしながら、httpd.confのすべての事項を.htaccessで制御できるわけではなく、一部のディレクティブは、設定が許可されていません。

    たとえば、今回、<Directory> ディレクティブを使用して、特定のディレクトリにのみBasic認証をかけようとしたところ、認証がかかりませんでした。

    原因は、.htaccessでは、<Directory> ディレクティブの使用が許可されていないからです。

    これは、なかなか不便ですが、サーバーの仕様であり如何ともしがたいです。

    これに対して、<Files> ディレクトリは、使用できます。アクセス制御(ORDER)等のために使われるものです。

    結論としては、CORESERVERの .htaccessにおいては、<Directory> ディレクティブは、不可だが、<Files> ディレクトリは可能ということです。

    もし、<Directory> ディレクティブも使えるという方法がありましたら、ぜひコメントをお願い致します。

    以上です。