濁点(゛)と半濁点(゜)を含む日本語のメール文字化け対応

JIS(≒ISO-2022-JP)で定義されていない文字コードは、UTF8から変換しても、もちろん正常に表示されません。

しかし日本語のUTF8には、実は、濁点と半濁点をふくむ文字に2パターンの表示方法があります。

たとえば「が」というひらがなですが、普通は、

xE3x81x8C

となります。

しかし、UTF8の決まりでは、

xE3x81x8B + xE3x82x99 (「か」+「 ○゛」)

でもOKなのです。

 

うちでは日本語文字コードの変換にUnicode::Japaneseを使ってます。非常に多くの変換パターンが実現できるので便利なのですが、上記の後者の場合(「か」+「 ○゛」の場合)に、UTF8→JISなどの変換に失敗します。

失敗というか、厳密にはxE3x82x99( ○゛)とxE3x82x9A( ○゜)が未定義状態のようで、「が」は「が」のように変換されてしまいます。

エンコーダを変えればいいのかもしれませんが、やはりバグが怖いので、下記のようにJISへの変換前にコードを統一することで対応してます。

 

ご自由にコピペどうぞ。

 

 

参考サイト)

http://d.hatena.ne.jp/kamosawa/20151015

http://www.seiai.ed.jp/sys/text/java/utf8table.html

http://webmastertool.jp/other/utf.html

http://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/u3040.html

非効率なサブクエリを改善する

サブクエリを使った検索において、検索件数が数百~数千程度であれば、マシンの力で何とかなることがあるが、この検索結果が数万単位の膨大な数となる場合、動作が極端に遅くなる場合がある。

例として、historyテーブルにメールの履歴、clickテーブルにメールの履歴番号をhistory_idとしたクリックURL、およびそのクリック回数が入っていて、レコードは複数あるとする。

historyテーブルにクリック数のデータはないので、clickテーブルを結合して、履歴データと、その履歴ごとのクリック数およびクリック率(CTR)の一覧を表示したい。またCTRの大きさで一覧をソートしたい。

例えば下記のSQL。

この場合、clickテーブルのレコードが膨大になってしまうと、10~15行目のサブクエリ内のSELECTが全数検索になるため、結合後のテーブルが巨大となり、極端に動作が重くなる。history_idにINDEXを貼っていても、数万単位の量になってくると、同様だ。

いくら最後(18行目)にLIMIT句でレコード数を制限しても、内側のサブクエリから処理されるので、結合時点ではテーブルは巨大になってしまう。

「サブクエリ内でLIMIT使えばいいのでは?」と思うが、1つの履歴番号に紐付くclickテーブルのレコードが必ず存在するとは限らないし、存在したとしてもレコード数は一定ではないためこの時点でLIMITは確定できない。

つまり、「GROUP BY history.id」(15行目)したレコード数が、30になるとは限らない。仮にサブクエリ内で同じく「LIMIT 0,30」とやったとしたら、結合時にデータに不整合が生じる可能性がある。

またCTRは、historyテーブルに存在する読者数がわからないと出せないので、結合後にORDER BYするしかなく、サブクエリ内ではCTRによるORDER BYができない。この理由もありLIMITは使えない。

そこで発想の転換をして、clickテーブルにhistoryテーブルを結合してみる。

ポイントは、

  • clickテーブルを基本として、クリック数の合計とCTRの計算をする。
  • historyテーブルをRIGHT JOINして、historyテーブルのレコード数に、最終的な結果レコード数をあわせるようにする。
  • ORDER BY の対象を「click.history_id」ではなく「history.id」とし、履歴番号に紐付くclickテーブルのレコード数がない時も、対応できるようにする。

こうすることで、サブクエリを使わずに、LIMITをうまく使って膨大なクリックデータを高速に処理できるようになった。

当然ページ送りも、このLIMITの値を変更するだけで対応できる。

 

経験上、どうしてもサブクエリを使わなければならないってことはほとんどないんだよなあ、、、(経験不足なのか?)。

大体の場合、上記のように結合の方法を工夫するか、テンポラリテーブルを使って処理できる場合が多いと思う。(個人の感想です)

 

参考サイト)

http://nullnote.com/programs/mysql/join/

SQLでサブクエリを上手に使う6パターン