アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

非エンジニアのWebディレクターにオススメのGUIツール(Windows) MySQL/PostgreSQL編

こんにちは、鴨田です。

大分久しぶりの投稿になりますが、今回はコマンドラインが苦手な非エンジニアのWebディレクターにオススメする、MySQLPostgreSQLGUIツール「HeidiSQL」をご紹介いたします。



インストールの前に



これから行う説明に関して、PuTTYなどで普段からリモートサーバーへ接続を行っている前提で、話が進んだりしますので、その点だけご注意をお願いします。ローカル環境であれば、特に気にしないで問題ありません。また、今回の説明はMySQLを用います。



インストール



まずはHeidiSQLのサイトから、インストーラーをダウンロードします。

http://www.heidisql.com/download.php


「Installer」ボタンをクリックすると、最新版がダウンロードできます。32+64bit installerになっているので、OSのバージョンは気にしないでも大丈夫です。今回は、バージョン9.2.0.4948を使用します。

インストーラーを起動すると、こんな画面が表示されます。


インストール方法で気をつけるところは特にありません。どんどん進めます。


インストールが完了すると、この画面になります。早速起動して、設定を行いましょう。



設定



起動すると、こんな画面が表示されます。


「Unnamed」セッションを選択して、接続したいデータベースの情報を入力します。

○ローカルPC内のDBに接続する場合

[設定]タブ
ネットワーク種別:MySQL(TCP/IP)
ホスト名 / IP:127.0.0.1
ユーザー:DBのユーザー名
パスワード:DBのパスワード
ポート:DBのポート番号
データベース:DB名

DBを作成したときに設定した情報を入力してください。リモートサーバーの場合もほぼ同様で、「Hostname /IP」をサーバーのIPに変えるだけです。

SSH経由でリモートサーバーに接続する場合

[設定]タブ
ネットワーク種別:MySQL(SSH tunnel)
ホスト名 / IP:リモートサーバーのIP
ユーザー:DBのユーザー名
パスワード:DBのパスワード
ポート:DBのポート番号
データベース:DB名

[SSHトンネル]タブ
plink.exe:PuTTYplink.exeを参照
SSHホスト+ポート:踏み台サーバーのIP:port番号
ユーザー名:踏み台サーバーのユーザー名
パスワード:踏み台サーバーのパスワード
秘密鍵ファイル:踏み台サーバーの秘密鍵を参照
ローカルポート:ローカルポート番号

リモートサーバーの情報は、インフラエンジニアに聞くか、プログラムのDBの接続設定を覗いて、入力してください。踏み台サーバーの方は、PuTTYなどの設定を流用してください。

設定が完了したら、「保存」ボタンを押して、セッション情報を保存しておきましょう。



テーブルの内容表示



データベースに接続すると、画面表示が変わります。


画面左側にデータベースのテーブルが表示され、画面右側に選択したテーブルの詳細が表示されます。画面下部はGUIで操作した内容のコマンドなどが出力されます。

サンプルとして、郵便番号情報を格納した「post」テーブルを用意しました。約125000件のカラムが格納されています。

データの中身を見るには、画面左側のビューで「post」テーブルを選択します。


画面右側のビューでは、「データ」タブをクリックします。
すると、テーブルの内容が見られるようになります。




検索(フィルターパネル)



該当のテーブルから、検索したい文字列を含むカラムを絞り込みたいときは、フィルターパネルを表示します。メニューから「編集」→「フィルターパネル」を選択するか、「Ctrl+Alt+F」です。


パネルに、検索したい文字列を入力すると、カラムが絞り込まれます。




並び替え



カラムを並び替えることも出来ます。


並び替えパネルをクリックし、表示されたウィンドウで、「カラムの追加」をクリックすると、フィールドの選択をすることが出来ます。フィールドを選択したら、「ASC(昇順)」、「DESC(降順)」をトグル式で選択し、「OK」ボタンを押すと、データが並び替えられて表示されます。




データの操作



データの変更は変更したい値のところで、シングルクリックを2回(ゆっくりダブルクリック)すると、データを編集することが出来ます。


データの編集が終わったら、Enterもしくは違う場所をクリックすると、編集が完了します。


この状態だとまだ変更が確定していない(左上に赤い三角マークが付いている状態)ので、違う場所をクリックなどすると、コマンドが流れて確定します。


データのコピーや貼り付けなどは、右クリックから行うことが出来ます。NULLの挿入も右クリック→値の挿入→NULLで可能です。同様に、行の追加や削除などをすることが可能です。




データの取得範囲



初期設定では、カラムの取得件数は1,000件となっており、「次」で、次の1,000件を取得したり、「すべて表示」で10,000件まで取得します。

レスポンスが遅くなりますが、この設定は変更することが出来ます。メニューからツール→環境設定を選択してください。「Text formatting」タブを選択し、「Number of rows displayed in data tab(Step, Maximum)を変更してください。




以上です。

他にも、いろいろ機能はあるのですが、基本的な使い方のご紹介でした。なにか問題が起こったときの調査や、テスト時にデータベースの内容を変更したいときなどで使う分には、この程度の操作で充分だと思います。

次回は、GitのGUIツールをご紹介したいと思っています。それではまた。

はじめから!リレーショナルデータベース:テーブル作成

こんにちは、志田です。
前回に引き続き、リレーショナルデータベースについてはじめから勉強していきましょう。

前回のまとめ





テーブルは、縦方向に並ぶ情報である「列」と、横方向に並ぶ「行」からなることを、前回勉強しました。
また、この縦方向に並ぶ「列」に対し、データの「型」を決めました。

今回は、まずデータベースを作り、そこに表を追加してみましょう。

データベースの作成



まずはデータベースを作成し、そこにテーブルを作るのが基本のやり方です。
Excelでいうと、新しいExcelのファイルを作ってブック(データベース)を作成し、シート(テーブル)を作るという動作に似ています。

では、MySQLに接続して、データベースを作成してみましょう。



mysql> CREATE DATABASE client;


CREATE DATABASE データベース名;
このコマンドでデータベースを作成することができます。

大文字のコマンドは全て、MySQLの命令や、予約語といって、特別な意味のある単語です。
(命令の書き方としては、小文字でもOKです。
 命令と自分が入力する内容の区別がつきやすいので、ここでは大文字を使うことにします)

命令の終わりには、「;」を付けて、命令文が終わりであることを示します。

こうして、データベースをいくつでも作成することができます。


データベースの利用



私達がExcelのファイルを操作するときも、どのファイルを開くか指定するように、
データベースにおいても、どのデータベースを使うか、命令する必要があります。



mysql> USE client;


USE データベース名

このUSEコマンドは、使うデータベースを切り替えることができます。

接続した直後の状態だとMySQLは、入力されたデータベースを操作するコマンドを
どのデータベースに対して実行してよいかわからないため、
こうして利用するデータベースを指定してやる必要があります。


表の作成



では、clientデータベースに表を作成してみましょう。

今回作成する表は、前回までに設計を行った、会社テーブル、部署テーブル、課名テーブル、担当者テーブルです。
表の作成は、CREATE文を使います。

まずは、会社テーブルを「company」として作成します。



mysql> CREATE TABLE company(
    ->   id      INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    ->   name    VARCHAR(255) NOT NULL,
    ->   address VARCHAR(255) NOT NULL,
    ->   tel     VARCHAR(15) NOT NULL
    -> );


表を作成するコマンドは、次のような文法になっています。

CREATE TABLE テーブル名 (カラム名 制約、オプション…);

前回までに考えたテーブルの構造と型の他に、「制約」というものが登場しました。
制約とは、そのカラムの決まりです。

例えば、companyテーブルの各カラムには「NOT NULL」という制約がついています。
これは、データを入れるときに、データがNULLではダメですという意味です。

NULLは、なにもない状態であることを指しています。
例えば、「0」は数字のゼロで、「」は文字がないという意味の空文字を示しています。
値そのものが入っていないことを表すのに、そのままでは表しにくいので「NULL」と表現しています。

companyテーブルでいうと、どのカラムも空ではいけない、なにかしらの値を入力しなければダメという意味です。

それから、idカラムには「PRIMARY KEY」という制約がついています。
これは、「このカラムはこの表で一意な値だ」
つまり、このidさえ指定すればレコードを指定できる、というカラムに対してつける制約です。

また、オプションというのは、カラムに補助的につける、まさにオプションです。
例えば、次の表で示す中にある「デフォルト」などは、有名なオプションのひとつです。

制約やオプションはこの他にもいくつかあります。
制約書き方意味
デフォルトDEFAULT 0
DEFAULT 'test' など
このカラムに何もデータを指定しないとき、デフォルトで入る値を指定します。
自動採番AUTO_INCREMENT自動で、1から順に連番をつけます。idなどのカラムに利用すると便利です。
ユニークUNIQUE列の中で、他と同じ値が取れないことを示します。例えば、ログインメールアドレスやユーザー名など、他の人と被っては困るものに付けます。


ということで、companyテーブルは、
・会社ID = id:データを入れれば自動で数字が割り振られる。companyテーブルの中で一意な値で、他と被ってはいけない
・会社名 = name:255文字までの可変長文字列で、空になってはいけない。
・会社住所 = address:255文字までの可変長文字列で、空になってはいけない。
・会社電話番号 = tel:15文字までの可変長文字列で、空になってはいけない。

というような構造の表になりました。
その他の表も、同じように作成してみます。

部署テーブルを、「group」として作成してみましょう。



mysql> CREATE TABLE group(
    ->   id          INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    ->   company_id  INT NOT NULL,
    ->   name        VARCHAR(30) NOT NULL
    -> );
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'group(
  id          INT PRIMARY KEY NOT NULL,…(略)


作成しようとしましたが、エラーが出て作成出来ませんでした。
MySQLは、エラーのある付近を示してくれています…
どうやら、「group」という名前がよくなかったようです。

このように、MySQLでは、MySQLが使う命令語を「予約語」としているため、
予約語をテーブル名にすると、エラーが表示されます。

予約語は沢山ありますが、うっかり使ってしまいそうな単語は
select, create, in, by, group, from などでしょうか。
他にもあるので、テーブル名を決める際には確認してください。

では、groupsがエラーで作成できなかったので、「groups」にして作成しましょう。



mysql> CREATE TABLE groups(
    ->   id          INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    ->   company_id  INT NOT NULL,
    ->   name        VARCHAR(30) NOT NULL
    -> );


今度はうまくいきました。
続いて、残りのテーブルも作成します。

課名テーブル sections


mysql> CREATE TABLE sections(
    ->   id        INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    ->   group_id  INT NOT NULL,
    ->   name      VARCHAR(30) NOT NULL
    -> );
Query OK, 0 rows affected (0.00 sec)


担当者テーブル persons


mysql> CREATE TABLE persons(
    ->   id          INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    ->   section_id  INT NOT NULL,
    ->   name        VARCHAR(30) NOT NULL,
    ->   email       VARCHAR(255) NOT NULL,
    ->   gender      ENUM('male', 'female') NOT NULL,
    ->   tel         VARCHAR(15),
    ->   date        DATE NOT NULL,
    ->   memo        TEXT
    -> );
Query OK, 0 rows affected (0.00 sec)


これで、全てのテーブルを作成することができました!
作成したテーブルの一覧を見るには、このコマンドを発行します。

SHOW TABLES;



mysql> SHOW TABLES;
+------------------+
| Tables_in_client |
+------------------+
| company          |
| groups           |
| persons          |
| sections         |
+------------------+
4 rows in set (0.00 sec)


4つの表ができていることが確認できました。
では、この表がどんな構造だったのか確認してみます。

表の構造を確認するには、このコマンドを発行します。

DESCRIBE テーブル名;
または
DESC テーブル名;



mysql> DESCRIBE company;
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
| name    | varchar(255) | NO   |     | NULL    |                |
| address | varchar(255) | NO   |     | NULL    |                |
| tel     | varchar(15)  | NO   |     | NULL    |                |
+---------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)


この表ではそれぞれ、以下の情報を示しています。
・Field:カラム名
・Type:型
・Null:NOなら、NOT NULL(NULLはダメ)。YESなら、NULLが入ってもOK
・Key:キー項目であるかどうか。PRIがついていれば主キーであることを示す
・Default:何も指定されていなかったときにデフォルトでとる値
・Extra:その他、付けられているオプション

このようにして、データベースを作成し、テーブルを作り、テーブルの構造を確認しました。


テーブルの修正



作成したテーブルですが、後から見返すと、おかしなところを発見しました。
personsテーブルのemailカラムにNOT NULL制約がついています。

今の時代、メールアドレスを持たない人は珍しいですが、
それでもまさとしが先週もらった名刺には、メールアドレスがないものもありました。
ここは、メールアドレスは必須入力ではなく、任意入力にすべきです。
データベースを修正しましょう。

データベースの修正には、以下のコマンドを使います。
ALTER TABLE テーブル名 MODIFY 直したいカラム名 制約、オプション;

実際に、personsテーブルにコマンドを発行します。



mysql> ALTER TABLE persons MODIFY email VARCHAR(255);


イメージとしては、カラム情報の上書きです。
もともと、emailというカラムにはNOT NULL制約がついていましたが、
制約がない状態でカラムを上書きしました。

では、テーブルの構造が変わったかどうか、確認します。



mysql> desc persons;
+-----------+-----------------------+------+-----+---------+----------------+
| Field     | Type                  | Null | Key | Default | Extra          |
+-----------+-----------------------+------+-----+---------+----------------+
| id        | int(11)               | NO   | PRI | NULL    | auto_increment |
| setion_id | int(11)               | NO   |     | NULL    |                |
| name      | varchar(30)           | NO   |     | NULL    |                |
| gender    | enum('male','female') | NO   |     | NULL    |                |
| email     | varchar(255)          | YES  |     | NULL    |                |
| tel       | varchar(15)           | YES  |     | NULL    |                |
| date      | date                  | NO   |     | NULL    |                |
| memo      | text                  | YES  |     | NULL    |                |
+-----------+-----------------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)


きちんと変更され、emailのNULLがYESになっていることがわかりました。


今回のまとめ



今回は、以下の3つのことを学びました。
・データベースの作成
・データベースにテーブルを作成
・テーブルの構造を確認
・テーブルの構造を修正

データベースやテーブルを作るのは重要な作業ですが、
テーブルの構造を確認したり修正することで、
新しい修正事項などに、より柔軟に対応できます。

はじめから!リレーショナルデータベース:型を考える

こんにちは!志田です!
前回にひきつづき、リレーショナルデータベースをはじめから勉強していきましょう。


前回のまとめ



とっても便利なデータベースには、いろいろな種類があります。
アシアルブログの笹亀の記事でも、RDBとは違ったNoSQLについての説明がありました。
その中でも、一番ポピュラーなリレーショナルデータベースについて、勉強していきました。

前回は、がんばる企業戦士まさとしが、紙の取引先情報からデータベースの構造について分類をしていきました。
これを、「正規化」といいます。
正規化をすることで、無駄がなく、情報を更新したときに異常が起こらない、柔軟なデータベースを作ることができます。


行と列





前回作った表のひとつをみてみましょう。
表なので、行と列があります。
データベースでも、縦に伸びるデータを行(カラム)、横に伸びるデータを列(レコード)といいます。
レコードが1件1件のデータになります。
カラム名というのは、カラムにつけた名前です。見出しのようなものですね。

カラムは縦に見ればわかるとおり、全て同じデータ(数字、文字など)になっています。
このカラムに対してつけるのが、「」です。


MySQLの型



では、MySQLで使える型を見て行きましょう。

日本語でいうとMySQLでいうと用途
短い整数型tinyintフラグの処理などに使う。男なら1、女なら0など
整数型int数字に使う。会員番号や通し番号など。
浮動小数点型float, double体重など、小数点が必要な数字に使う。
固定長文字列型char(N)桁数の決まっている文字列。Nに文字数を入れる。郵便番号だと「113-0033」で8文字なので、char(8)
可変長文字列型varchar(N)>桁数の決まっていない文字列。255文字までならこれを使う。名前、住所など。名前だと長くても20文字くらいなので、varchar(20)
長い可変長文字列型textメモ、日記の本文など、長い文字列に使う。
日付型date日付に使う。誕生日など。「2012-10-04」
日付時刻型datetime日付と時刻を一緒に扱う。会員登録日などに使う。「2012-10-04 10:23:40」
文字列定数型enum('value1', 'value2',...)リストから選>ぶ形式の型。男=male、女=femaleだと、enum('male', 'female')となり、どちらかを指定する。


他にももっとたくさんの型があり、使い方や指定の方法などいろいろなのですが、
今回はよく使うこれらの型をご紹介しました。

文字列の「桁数」という概念が、ちょっとわかりにくいかもしれません。
例えば、紙の表を思い浮かべて下さい…。
「会社住所」の欄があまりに小さかったら、住所が全部書けませんよね。
ものにはそれぞれ、適切な欄の長さ・大きさがあります。
適切な文字数を決めることはつまり、桁数を決めるということです。

データベースを作る時は、テーブルの正規化を行い、正規化したテーブルに型をつけるという手順で作ります。
では、まさとしさんが、前回のテーブルにどのような型をつけたのか、みてみましょう。

まさとし 型をつける





まず、前回のテーブルの上から考えていきます。

会社テーブル

会社テーブルは、「会社ID」「会社名」「会社住所」「会社電話番号」からなります。
「会社ID」は数字なので、int型がよいでしょう。
「会社名」は、どんなに長くても255文字を超えるようなものはなかったので、varchar(255)にしましょう。
「会社住所」も同じく、長さは255文字程度あれば充分ですので、varchar(255)にします。
「会社電話番号」は、数字だけでできてるな、とまさとしさんは思いました。
・・・でも待てよ、市外局番は0から始まるものもある。それを整数型で扱ったとしたら、先頭の0が無視されちゃうのでは?

そうです。数字からなるデータでも、先頭の0が重要になってくるものは、
「計算のできる数字」でなく、「数字の文字列」にするのが良いです。
「会社電話番号」は、11桁の文字列であるvarchar(11)にしました。

部署テーブル、課名テーブル

部署テーブルと課名テーブルも同様に、
部署ID、会社ID、課ID、部署IDはint型、部署名、課名はvarchar(255)にしました。

担当者テーブル

担当者テーブルは、情報がたくさんあって大変そうです。
まず、他のテーブルと同じように、担当者ID、課IDはint型にし、名前はvarchar(20)にしました。

性別は、表では男性、女性となっています。
まさとしさんは、「じゃあ、これはchar型でいいかな…」と思い、テーブル設計書にcharとメモしました。

そこへ、先輩が通りかかって訊ねました。
「まさとし、それ、間違えて女ってDBに登録しちゃったら、どうするの?
2つのうちのどちらかから選ぶなら、絶対間違えないような型のほうがいいんじゃないの?」

たしかに…。文字列にすると、入力間違いが怖いです。
そこで、まさとしさんはtinyint(1)を使って、男性なら1、女性なら0を入力させることにしました。
これなら、1か0のどちらかしか選ぶ必要はないので、安心です。

「まさとし、それ、お前は1と0でわかりやすいからいいだろうけど、他の人が見たらわかんないよ?」

うう、先輩、確かに。
まさとしさんは、enum型を使い、男性か女性かをリストから選べるようにしました。
enum('male', 'female')とすることで、どちらかの値がDBに入ることになりました。

個人の電話番号は、会社電話番号を同じくvarchar(11)にしました。

日付というのは、名刺をもらった日のことを指しています。
これは、年月日だけがわかっていればいいので、date型にしました。

備考は、どのくらい長くなるかわかりませんから、text型にしました。


テーブル構造完成!





それぞれ考えた型を追記して、テーブル構造が完成しました!

このように、データベースを作るうえで大事な流れは、このようなものです。

(1) テーブルの構成を考える。
(2) 正規化をする。
(3) それぞれのカラムに適切な型をつける。

正規化をして表の構造を整えることも大事ですが、まさとしさんの先輩からの指摘のように、
そのカラムが取り得る値について考え、最適な型を考えるのも重要です。

では、次回は実際にデータベース上でテーブルを作り、操作を行なってみましょう。

はじめから!リレーショナルデータベース

こんにちは!ゲームだいすき志田です。
ゲームをやっていると、どのアイテムが足りないとか、自作キャラクターの性能だとか、
管理したいなぁってこと、ありますよね?ないですか?ありますね。

そんなとき、データベースを使いましょう!

今回は、DBとはなにか、というところと、簡単な正規化について勉強しましょう。


データベースとはなにか



とはいえ、最近、猫も杓子も「データベース」ですね。
…便利そうなのはわかるけど、DBってそもそもいったい何でしょうか。

データベースとは、Data Base、データの基地という意味で、
つまりはデータの集合です。

世の中には、いろいろな種類のデータベースがあります。
・リレーショナルデータベース(関係データベース)
・オブジェクトデータベース
・階層型データベース
・ネットワーク型データベース
・分散型データベース

この入門記事では、最もポピュラーでよく使う、「リレーショナルデータベース」を例にとり、説明していきます。
どのくらいポピュラーかというと、DBといったらリレーショナルデータベースを指すくらい有名なタイプのDBです。

なぜDBを使うのか



便利便利と言われているものの、なぜわざわざ新しいことを勉強してまで、DBを使うのでしょうか。
それは、こんなメリットがあるからです。

データの統合化・共有によるメリット

例えば、紙の社員名簿で社員を管理している会社を想像してください。
総務部で持っている社員名簿と、人事部で持っている社員名簿があったときに、
どちらかだけが更新されたら、データとしての一貫性が保てなくなります。

あっちの名簿にはAさんがいるのに、こっちにはAさんがいない!
Aさんは結局、いるの?いないの?ということになりかねません。
これが、統合化によるメリットです。
データはひとつにまとめましょう、ということです。

もうひとつのメリットが、共有です。
データと、それを扱うプログラムが独立していると便利なのです。
給与計算プログラムと日報プログラムといった、別のシステムが動いているときに、
どちらも同じ社員名簿DBを参照していると、先ほどのような一貫性がない状態を避けられます。

うーん、なんて便利なんでしょう…!

データベースシステムの構成



では、そのデータベース。どういった構成になっているのかを見てみましょう。



ユーザやシステムが、「名簿一覧が欲しい」と命令をします。
この命令をDBMS(Data Base Management System/データベース管理システム)が受け取ります。
DBMSはDBから、その命令に合ったデータを取得して、ユーザに返してあげます。

世間で、MySQLOracle…などと言っているのは、このDBMSの製品名です。
DBMSはHDDに格納されている実際のデータを管理し、命令を理解して結果を返しているのです。


まさとし はじめてのデータベース



HP作成の業務を終えたまさとしさんに、また新たな仕事が舞い込んできました。
「まさとし君、うちの会社の取引先リスト、データベースにならんかね?」

まさとしさんの会社の取引先リストは、なんと紙だったのです!
紙で管理していると、どこの会社のダレソレさんは退職しただの、住所移転しただの、
そういった情報がごちゃまぜになってしまいます。
それに…先輩の字はミミズがのたくったようで、全然読めないんです!

「わかりました、やってみます!」
がんばれまさとし!

まず、まさとしさんは、紙の情報を整理することにしました。



取引先リストを紙にまとめると、このようになりました。
「データベースに載せる項目は、こんなモンでいいかな…」

すると、まさとしさんの後ろを先輩が通りかかりました。

「おっ、まさとし、それって非正規形の表だね!」

非正規形の表とは



非正規形の表とは、更新異常が起こってしまう表のことをいいます。
更新異常には、3つの種類があります。

(1) 変更異常
情報を変更するとき、重複したすべての情報を変更しないと矛盾が発生してしまうことをいいます。
例えば、株式会社 とりもち商事の住所が変更になったら、どうなるでしょうか?
この表のうち、会社名が「株式会社 とりもち商事」であるデータ全ての住所を変更しなくてはなりません。
とても面倒です。

(2) 挿入異常
項目が混ざっているために、新しいデータを追加できない異常のことをいいます。
例えば、「新しく取引先を追加したい、だがまだ担当者はいない」という場合、この表にデータを追加することはできません。
(会社の情報と担当者の情報がいっしょくたになって入っているからです!)

(3) 削除異常
削除をしたときに矛盾が発生してしまうことをいいます。
例えば、「株式会社 とりもち商事」のデータは2件ありますが、高木さんと赤坂さんが退職された場合、
この表から2人の情報を削除してしまうと、とりもち商事の会社データ自体もなくなってしまいます。

つまり、非正規形の表がイケナイのは、なんでもかんでもごちゃまぜにしているからなのです。


正規化をする



ではこの非正規形の表、どうやったらいいかんじの表になるのでしょうか。
いいかんじの表にすることを、「正規化する」といいます。
正規化するとはつまり、ごちゃまぜになった表を分割して、わかりやすく、扱いやすくすることです。

正規化には、分割の段階によって、第一正規形、第二正規形、第三正規形、Boyce-Codd正規形(ボイス・コッド正規形)、第四正規形、第五正規形という種類にわかれています。
ただし、実際の業務においては、ボイス・コッド正規形や第四、第五正規形を行うことはあまりありませんので、
第一正規形から第三正規形まで、流れでできるようになりましょう。
慣れてしまえば、非正規形の表からすぐに第三正規形の表を導けるようになります。

第一正規形



第一正規形とは、重複して現れる部分を分離することです。
先ほどの表でいうと、重複しているのはどこでしょうか。
そう、「会社名、会社住所、会社電話番号、部署名、課名」が、名刺をくれた社員さんごとに重複していますね。
まずは、これを、値の集合のない表にしてみます。



会社と社員を分けて考えることで、ずいぶんすっきりしました。

ここで、関数従属性について考えてみます。

関数従属性



関数従属性とは、Aの値を決めるとBの値が決まるというものをいいます。

例えば、「会社名がわかれば、会社の住所と電話番号がわかる」
「会社名がわかれば、その会社に存在する部署がわかる」
「部署がわかれば、その部署に存在する課名もわかる」
「名前がわかれば、性別、メールアドレス、個人電話番号、登録日、備考がわかる」

では、このAがわかればBがわかるという関係ごとに、表を分割してみましょう。


第三正規形



関数従属性をもとに、表を分割してみました。



こう分けることで、会社の中に部署が、部署の中に課が、課の中に社員がいる、という関係が流れるようにわかりますね。

それぞれ、会社や部署には一意となるIDを振って、全体を眺めた時にわかりやすくしました。

会社IDが1である、「株式会社まーべらす」には、部署ID1と2である営業部、開発部がある。
営業部には営業課、開発部には製品開発課があり、
営業課には山口さん、田中さん。製品開発課には竹田さんがいる。

関数従属というと意味がわかりにくいですが、要は、マスタファイルを作るということなのです。
会社の情報は、会社マスタファイルだけで修正すれば楽ちんですね。

こうして、個々のデータ同士の関係を切れるぶんだけ切っていくことが、正規化するということです。

では、次回はこの正規化したテーブルをもとに、型について考えて行きましょう。

Further adventures with Zabbix

Following on from my last blog about installing Zabbix I thought I'd go into it in a bit more depth this time because, as it turns out getting it installed and running is really just the beginning.

The problem is that all the servers are doing different jobs and have subtle differences in the way they're configured. Therefore while you can start getting feedback from Zabbix very quickly I've had to spend a fair bit of time tweaking it for our environment.

The main issue is that the templates supplied by Zabbix are very detailed and the alerts have low trigger thresholds. This is exactly what you need to get started but it doesn't take long to start collecting a large number of alerts, most of which will be false. Getting a red alert that a server was down was alarming until I realised it was for a news server, something we don't actually run. Clearly some template editing was called for.

This can be quite formidable at first sight but fortunately because the supplied ones are so detailed its mostly a case of taking a hatchet to everything you don't need, at least until you're comfortable with Zabbix. So from the (literally) thousands of things you can monitor in almost all cases the important ones will be

Disks and filesystems
CPU load
Memory
Services

Disk performance metrics are really concerned with availability and I/O performance. Its always good to know there's enough free disk space on your partitions. I find it more helpful to show this as a percentage of available space than an absolute figure in Mbs. You will also want to monitor reads and writes per second. Actual values are a bit geeky in themselves but over time they'll build up into useful historical trends.

CPU performance? Well clearly you need to know how hard the processors are working so keep an eye on CPU load average and idle time. Load average is normally expressed in values over 1, 5 and 15 minutes. A value of 0.7 (meaning the processor is at 70% capacity) or below is good, occasional peaks as high as 3 are probably OK too, anything higher than that, especially if it's sustained spells trouble. In the default configuration these metrics returned a blizzard of alerts but are now more or less under control (more about that in a moment).

Memory, this covers both physical RAM and virtual memory. Generally what doesn't fit into RAM is swapped so you should keep an eye out for high swap rates.

And services will depend on what function your server is performing, but Zabbix can ping your HTTPD or MySQL service regularly to make sure its still there.

Once everything seemed to be under control I was pretty alarmed to discover that load on the Zabbix server itself had gone through the roof. My next job therefore was to reduce the load on the server.

This screen shows what happened when I deployed a fairly basic monitoring template across the servers based on the supplied one for Linux



As you can see the Zabbix server struggled to keep up for a while before gradually losing the battle. Well fter a bit of research I found I only had to do two things.

First of all a bit of tinkering with MySQL's configuration file (/etc/my.cnf)
Adding these two lines reduced CPU utilization by 50%!

innodb_buffer_pool_size=256M
innodb_flush_method=O_DIRECT

The next step was to reduce the polling time for the monitored items dramatically. The default for many is every 30 seconds. Multiply this by 40 different metrics on 50 servers and its not hard to see why the server was struggling to keep up.

By throttling back the the polling threshold to once per minute on many values and considerably more than that on others. You really don't need to check free disk space more than once every 15 mins or so. By doing this I was able to reduce CPU utilization by another 50%.

So load on the server reduced by over 100%. Here is a screenshot of the result of these two steps. Right now MySQL is taking up 2% of the CPU resources, against about 130% last week!



MacにgroongaのMySQL用ストレージエンジン

こんばんは。笹亀です。

2年間お世話になった神楽坂からお引越しをすることになりました。
名前がカッコいいからと言う単純な理由から選んだ割には、
だいぶいい街で快適に過ごさせていただきました。
ということで現在は家探し中です。

さて今日はgroonga(ぐるんが)のMySQL用ストレージエンジンを実際に使ってみたくなり、
インストールをしてみようと思います。

そもそもgroongaは今もまだ広く利用されている全文検索システムSennaの後継と言われています。groongaストレージエンジンはMySQLSennaを利用するTritonnの後継プロジェクトとなります。MySQLではver5.1からPluggable Storage Engineインタフェースが採用されたことで、
以前よりも柔軟に独自のストレージエンジンを利用できるようになりました。

上記のことからMySQL経由でもgroongaを利用できるようになるということです。groongaのMySQLストレージエンジンを経由するとgroongaをSQLコマンドでも利用することができるようになります。

それでは早速インストールしていこうと思います。当然ですが、MySQLの5.1とgroongaが既にインストールされている必要があります。
 ※自分の環境はMacなので若干パス情報などが違いますので、ご注意くださいませ。
 ※なお、MySQLのインストールは省略します。

まずはgroongaをソースをダウンロードしてインストールする。
http://groonga.org/download/からダウンロードし、適当な箇所に解凍します。
コンパイルをしてインストールします。


 ./configure --prefix=/opt
 make
 sudo make install
※正常にソースからインストール完了


groongaストレージエンジンのビルドしてみた。
http://github.com/mroonga/mroonga/downloadsからダウンロードし、適当な箇所に解凍します。

http://mroonga.github.com/tutorial.html#id3」のページを元にインストールを進めているときにここで意味深な説明分を発見した。
「with-mysqlMySQLソースコードディレクトリ」ということはソースをダウンロードしないといけないのか・・?と思い、MacPortsなので「/opt/local/var/macports/distfiles/mysql5/mysql-5.1.43.tar.gz」からコピーして展開し、展開先を設定しました。
"libdir"でMySQLバイナリのプラグインディレクトリ、
"with-groonga"でgroongaのインストール先を指定してconfigureを実行します。

最終的にこんな感じ


./configure --with-mysql= /Users/sasa/Public/src/mysql-5.1.43 --libdir=/opt/local/lib/mysql5/mysql/plugin --with-groonga=/opt


むむ。。。エラーが出るぞ。。
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking dependency style of g++... gcc3
checking how to run the C preprocessor... gcc -E
checking build system type... Invalid configuration `/Users/sasa/Public/src/mysql-5.1.43': machine `/Users/sasa/Public/src/mysql' not recognized

いろいろ調べてみる。。
どうやらソースからインストールされているMySQLのビルドしたソースが必要みたいだ。
MacPortsでインストールしたbuild先を探して確認してみる。




portdbpath
MacPorts がダウンロードしたソース、インストールされた ports のレシート、主要なレジストリといった作業データを保存するディレクトリ。'${prefix}' におけるパス名の制約と同じ制約があります。

ということは「opt/local/var/macports」内でbuildしていることがわかった。
上記箇所に移動してみるとbuildフォルダを発見。
過去にインストールしたアプリごとにbuildファイルがあることを期待して確認をしていましたが、見事に空っぽでした。インストールするごとに維持的な展開場所として利用するんだとうと勝手に解釈しました。

どうしても自分の環境にインストールしたかったのですが、見事にうまくインストールできませんでした。MySQLをソースからインストールしてMySQLのbuildソースがある状態でインストールしないといけないということがよくわかりましたが、ソースからインストールしか使えないというのはいかがなものかと思います。

yumなどでインストールした場合はgroongaのMySQL用ストレージエンジンはインストールできるんでしょうか?
 ※buildソースって保持しているのでしょうか?なんかうまく出来ない気がしています。

もし、この辺りの情報に詳しい方々、
知識不足の自分にご教授いただけますと幸いでございます。

最近頻繁に使用するMySQL関数など

こんばんは。笹亀です。

先週あたりからめっぽう寒くなってきました。
どうやら大寒波のおかげで心配されていた今年のスキー場の雪の心配はなさそうです。

さて、今回は頻繁に使うことを自分へのメモの意味でも記事にまとめさせていただきました。
みなさんの参考になれば幸いです。

ーーーMySQLシリーズーーー
■mysqldumpのオプション「--skip-extended-insert」
 データベースのデータ(INSERT)を1行のINSERT文にするのではなく、複数行のINSERT文として出力する

 自分が使った用途:ダンプを取ったデータを特定のキーワードでgrepするため

用途は限られますが、便利です。このオプションを見つけるのに少し苦労しました^^;

■REPLACE関数
 MySQLの文字列置換する関数

 自分が使った用途:データベース内の文字を一括で置換するため



  UPDATE hoge_t SET body = REPLACE(body, 'www.asial.co.jp', 'blog.asial.co.jp');

 「www.asial.co.jp」→「blog.asial.co.jp」に置換
 
間違えると悲惨なことになりますのでちゃんとバックアップしてから実行するようにしましょう。

■登録日から30日ごとに処理をするデータを算出する
 DATEDIFFとMOD関数を使ってSQLで算出する

 自分が使った用途:登録日から30日ごとに通知メールを送りたいときに使用



SELECT * FROM user WHERE MOD(DATEDIFF(now(),regist_date), 30) = 0 AND DATEDIFF(now(),regist_date) <> 0;

 DATEDIFFで現在の日付からの日数を算出して、30で割る
  →日数が0(登録日が当日)の場合は除く

[DATEDIFFの実行サンプル]


○○日ごとのデータを取得するときに非常に効果的、主にバッチ処理などで活用させていただいております。MySQLの関数は負荷を気にしなければ、組み合わせて次第でいろいろできて恐るべしです。

ーーーおまけ サーバインストール編ーーー
■MySQL5.1のCentOs5.4のyumでインストール時の注意事項
yum install mysql*」デフォルトでは5.077(2009/12/21現在)がインストールされるので、remi レポジトリを追加してMySQL5.1系をインストールしました。
下記の手順で更新する


wget http://rpms.famillecollet.com/el5.i386/remi-release-5-6.el5.remi.noarch.rpm
rpm -Uvh remi-release-5-6.el5.remi.noarch.rpm
yum --enablerepo=remi,epel,rpmforge update mysql*


MySQL5.1系を入れるとPHPも5.3系にアップデートされてしまう(困
本当はPHP5.2.11とMySQL5.1がよかったんですが。。。
困ったものです(でも結局、このまま押し切って使うことにしました


早いもので今回が今年最後のブログとなりそうです。
少し早いですが皆様、よいお年をお過ごしくださいませ。
来年度もよろしくお願い致します。

MacPortsのMySQLにQ4Mをインストールする方法

皆さん、こんばんは。笹亀です。

本日はブログを書くために環境をつくっているときに、間違えてMacPortでインストールしたものを削除してしまいました;;
悲しさとむなしさと戦いながらも本日のブログをお届けさせていただきます。
 ※そのため、内容はちょっと少なめになっています。ごめんなさい

今年のPHPカンファレンスでもQ4Mの発表があり、いつか使う日が来るだろうと思い、
個人的にもとても興味があったので実際に使ってみたいくなりました。


Q4M (Queue for MySQL) は MySQL 5.1 のプラガブル・ストレージ・エンジンとして動作するメッセージキューであり、堅牢・高速・柔軟であるよう設計されています。(転載させていただきました


早速インストールをと思ったのですが、上記のこともあり、今回はインストールのみの紹介です。

特にMacPortsMySQLをインスールしていて、そのMySQLQ4Mをインストールするときが大変でした。
さらにMacPortsでのQ4Mのインストールする説明サイトがあまりなかったので、
以下にまとめさせていただき手順についてご紹介させていただきます。

0.MacPortsMySQLの最新版をインストールします(mysql-5.1.39@2009/10/13現在

1.Q4Mの最新版のソースをダウンロードします。(http://q4m.31tools.com/dist/

2.mysqlのソースをコピーして展開しておきます(Q4Mコンパイル用)
  cp /opt/local/var/macports/distfiles/mysql5/mysql-5.1.39.tar.gz /var/tmp
  cd /var/tmp/
  tar xzvf mysql-5.1.39.tar.gz

3.mysqlのライブラリのシンボリックリンクlinuxの通常のインストール先に張る
  sudo ln -s /opt/local/include/mysql5/mysql/ /opt/local/include/mysql
  sudo ln -s /opt/local/lib/mysql5/mysql/ /opt/local/lib/mysql

4.コンパイルをします
  ./configure --prefix=/opt/local LDFLAGS=-L/opt/local/lib CPPFLAGS=-I/opt/local/include --with-mysql=/var/tmp/mysql-5.1.39 CFLAGS="-I/opt/local/include/mysql5/mysql -I/opt/local/include" CPPFLAGS="-I/opt/local/include/mysql5/mysql -I/opt/local/include"

5.makeとmake installする
  ※make install するときはsudoを付けないとパーミッションのエラーになるので忘れずに。

6.MySQLへインストールしたSQLを取込みます
  mysql5 -u root -p < support-files/install.sql

7.perlのテストスクリプトを実行する
  perl run_tests.pl
  ※それらしく実行されるはずです。

8.ちゃんとインストールされているか確認
  show plugins

9.インストールができて喜ぶw



linuxのサーバにインストールする場合ならばrpmも用意されており、ここまで苦労することはないはずです。
Q4Mの実装編も含みでご紹介させていただきたかったのですが、いろいろな問題に悩まされた関係上、次回に持ち越させてください。
次回をお楽しみにしていただけましたら幸いでございます。
本当にごめんなさい ><;

結構使えるMySQLのTrigger機能!

皆さん、ご無沙汰しております。
パソコン周辺機器にお金をかけはじめている笹亀です。

エンジニアはパソコンが商売道具なので、
やはり使いやすい物を使いたくなるのは自然な事ですね。
ご参考までに。。。
マウス  :Logicool MX Revolution(ビックカメラでポイントで購入
キーボード:Bluetooth Mac用キーボード(会社の人から売ってもらいましたw

今回はTriggerについてご紹介したいとおもいます。
Triggerとは、データの変更などのイベントによってあらかじめ指定した処理を自動的に実行する機能です。
最近使用しているデータベースには必ず備えてある機能です。
Oracle,Postgres,MySQLでも当たり前のようにあります。

実際にはどのようなときに使用するものなのでしょうか?
 ・特定のテーブルに対しての処理のログをとるため
 ・特定のテーブルのバックアップをとる
 ・子テーブルの内容が更新されたときに関連する親テーブルの情報を変更したいとき
このような場面ではTriggerを使うと便利かもしれません。

それでは、実際に今回はMySQLを使用してご説明していきたいとおもいます。
まずは、簡単なテーブルを作成しておきます。


■カテゴリテーブル
CREATE TABLE category_t (
  `id` int(10) unsigned NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `product_count` int(11) default 0,
  PRIMARY KEY  (`id`)
) DEFAULT CHARSET=utf8;
■商品テーブル
CREATE TABLE product_t (
  `id` int(10) unsigned NOT NULL auto_increment,
  `category_id` int(11) default NULL,
  `name` varchar(255) default NULL,
   PRIMARY KEY  (`id`)
) DEFAULT CHARSET=utf8;


カテゴリテーブルにはproduct_countというカテゴリに属する商品数をセットしておくフィールドを用意しておきます。
今回はproductテーブルにinsertしたときに自動的にこのフィールドに商品数を更新するTriggerを記述していきます。
Triggerの作成は「CREATE TRIGGER トリガ名」で作成します。逆に削除する場合は「DROP TRIGGER トリガ名」で行えます。
Triggerの作成は権限が無いユーザでは作成できないので、管理者(root)で作成しましょう。

それでは、早速下記のように作成してみます。


delimiter //
CREATE TRIGGER category_product_count AFTER INSERT ON product_t 
FOR EACH ROW 
BEGIN 
  UPDATE category_t 
  SET 
         product_count = (SELECT COUNT(*) FROM product_t WHERE category_id = NEW.category_id) 
  WHERE id = NEW.category_id;
END;//
delimiter ;


正しく登録できたかは「show triggers;」とコマンドで確認できます


上記のTriggerの意味は、
product_tテーブルにINSERTされた後にBEGINからENDまでの処理を行うという意味になります。
BEGINからENDまでの処理は登録した商品のカテゴリIDを使用して、category_tテーブルのproduct_countにカテゴリに属する商品数を更新するSQLです。
「NEW.category_id」は登録した商品のカテゴリIDになります。
ちなみに「OLD.category_id」で更新前のカテゴリIDを参照できます。

注意点としては、トリガ内で指定できる使用できる構文にはいろいろな制約があります。
LOCK TABLEやアクションを起こしたテーブルへの更新・追加・削除処理(ここの例だとproduct_t)が行えません。
詳しくは下記に記述されていますので、そちらを参照ください。
http://dev.mysql.com/doc/refman/5.1/ja/routine-restrictions.html

それでは実際に、insert文を発行して確認しましょう。
まずはカテゴリデータをいくつか準備します。


INSERT INTO category_t VALUES('1','category_name1',0);
INSERT INTO category_t VALUES('2','category_name2',0);
INSERT INTO category_t VALUES('3','category_name3',0);


次に商品を登録していきます。
Triggerの処理で商品を登録すると商品に属したカテゴリのproduct_countが更新されるはずです。


INSERT INTO product_t VALUES('1','1','product_name1');
INSERT INTO product_t VALUES('2','1','product_name2');
INSERT INTO product_t VALUES('3','2','product_name3');
INSERT INTO product_t VALUES('4','3','product_name4');
INSERT INTO product_t VALUES('5','1','product_name5');


category_tテーブルを確認するとカテゴリごとの登録されている商品数が更新されていますね。


このようにしてTriggerを作成していきます。
Triggerを使用する点の注意ですが、SQLの負荷を考えて作成を行わないと
パフォーマンスが落ちる場合もあります。
例えばキーにインデックスを張らずに大量のデータから検索した結果を更新するときなどです。
そのようなことを考慮して使用する分にはTriggerの機能をフルに生かせるのではないでしょうか。
皆さんもこの機会に是非、Triggerを使ってみてください。


■オマケ
こんな感じでプログラムっぽくIF文でSQLの処理を分けることもできます。
商品を更新したときに件数を調べて0件じゃないときと0のときで処理を分けてみました。
更新前のカテゴリIDの商品数と更新後のカテゴリIDの商品数を更新するTriggerです。
 ※IF文をかかなくても書けますが、ご愛嬌で。。


delimiter //
CREATE TRIGGER category_product_count_clear AFTER UPDATE ON product_t 
FOR EACH ROW 
BEGIN 
  IF (SELECT COUNT(*) FROM product_t WHERE category_id = OLD.category_id) != 0 THEN
    UPDATE category_t 
    SET 
           product_count = (SELECT COUNT(*) FROM product_t WHERE category_id = OLD.category_id) 
    WHERE id = OLD.category_id;
  ELSE
    UPDATE category_t 
    SET 
           product_count = 0 
    WHERE id = OLD.category_id;
  END IF;

  UPDATE category_t 
  SET  
        product_count = (SELECT COUNT(*) FROM product_t WHERE category_id = NEW.category_id) 
  WHERE id = NEW.category_id;

END;//
delimiter ;


■実行SQL
UPDATE product_t SET category_id='2' WHERE id = '5';

結果

Google MapsとMySQLの連携

こんにちは、アシアルの中川です。
Google Mapsに表示する情報をMySQLのgeometry型で扱う方法を試してみました。

Google Mapsのある地点にマーカーを表示したりすることがある場合、
緯度・経度の情報で地点に表示させることができますが、
データベースにこの情報を保存する場合、lat(float), lng(float)とそれぞれカラムに保存する方法もあるのですが、この方法では各データの位置の関係が非常に扱いにくくなります。
Google Mapsで表示されている範囲内のデータのみ取得したい場合や、
ある地点から近い順に取得する場合などに面倒なことになります。

そこで、MySQL4.1以降で用意されている空間情報を扱う機能の「geometry」型を使用します。
MySQL 4.1 リファレンスマニュアル :: 10 MySQL における空間情報の機能(日本語)」
MySQL :: MySQL 5.0 Reference Manual :: 11.12 Spatial Extensions(英語)」
MySQL :: MySQL 5.1 リファレンスマニュアル :: 16 Spatial Extensions(英語)」

※今回紹介する方法は、「鉄道模型のコミュニティ『トレイン・トレイン』」にて
先日リリースしたコンテンツ「鉄マップ」にも使用してみました。

テーブルの作成ですが、空間情報を扱うカラムの型を「geometry」と指定します。


CREATE TABLE `spot` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `latlng` geometry NOT NULL,
  `zoom` tinyint(2) unsigned default NULL,
  PRIMARY KEY  (`id`),
  SPATIAL KEY `spot_latlng_index` (`latlng`)
) ENGINE=MyISAM;


空間情報用のカラムにインデックスを作成するためには、「InnoDB」でなく「MyISAM」を使用し、
「SPATIAL」キーワードを使いインデックスを作成します。
また、対象のカラムが「NOT NULL」宣言がされている必要があるようです。

これで、準備ができました。次にデータを登録してみましょう。

通常のINSERT文の発行で行えるのですが、geometry型のカラムにデータを入れるためには、変換用に用意されている関数「GeomFromText」を使用します。


mysql> INSERT INTO `spot` (`name`, `latlng`, `zoom`) VALUES ('アシアル株式会社', GeomFromText('POINT(139.762522 35.706752)'), 19);

mysql> SELECT * FROM spot;
+----+--------------------------+---------------------------+------+
| id | name                     | latlng                    | zoom | +----+--------------------------+---------------------------+------+
|  1 | アシアル株式会社         |        @`xa@              |   19 |
+----+--------------------------+---------------------------+------+

上記にようにそのまま、取得しようとすると、geometry型がおかしな状態で表示されると思います。

緯度経度を取り出すときには関数(X, Y, AsTextなど)を使用し、以下のように変換して取得することができます。



mysql> SELECT id, name, X(latlng) as lng, Y(latlng) as lat, zoom, AsText(latlng) as geomtext FROM spot;
+----+--------------------------+------------+-----------+------+-----------------------------+
| id | name                     | lng        | lat       | zoom | geomtext                    |
+----+--------------------------+------------+-----------+------+-----------------------------+
|  1 | アシアル株式会社         | 139.762522 | 35.706752 |   19 | POINT(139.762522 35.706752) | 
+----+--------------------------+------------+-----------+------+-----------------------------+


データベースの準備ができたところで、次はGoogle Maps側です。



var lat = 35.706752;
var lng = 139.762522;
var zoom = 19;

//マップを作成し、中央を指定位置にセットする。
var map = new GMap2(document.getElementById("map-canvas"));
map.setCenter(new GLatLng(lat, lng), zoom); 
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.addMapType(G_SATELLITE_3D_MAP);

//指定位置にマーカーをセットする。
var marker = new GMarker(new GLatLng(lat, lng));
map.addOverlay(m);


Google Mapsで表示しているエリアの情報を以下のように取得できます。



var options = {};

//センターとズーム情報取得
var center = map.getCenter();
options['lng'] = center.lng();
options['lat'] = center.lat();
options['zoom'] = map.getZoom();

//表示範囲情報
var latlngbounds = map.getBounds();
var sw = latlngbounds.getSouthWest();
var ne = latlngbounds.getNorthEast();
options['bounds[swlat]'] = sw.lat(); //南西の緯度
options['bounds[swlng]'] = sw.lng(); //南西の経度
options['bounds[nelat]'] = ne.lat(); //北東の緯度
options['bounds[nelng]'] = ne.lng(); //北東の経度


JavaScriptで取得したデータをAjaxなどでサーバに投げてやります。
取得するタイミングは以下のようにイベント発生のタイミング等指定できます。



GEvent.addListener(map, 'dragend', function(){
  //マップのドラッグ移動終了後
  // ここで位置・範囲取得やajax等の処理をする
});

GEvent.addListener(map, 'zoomend', function(){
  //マップのズーム変更終了後
  // ここで位置・範囲取得やajax等の処理をする
});

※詳細につきましては、「Google Maps APIリファレンス」を参照してください。

以上のようにGoogle MapsなどからAjaxでサーバ側に送信した地点や、範囲などの情報を使う際に、MySQLの「geometry」型の威力が発揮されます。

Ajax送信やサーバ側の受信のコードはここでは、触れませんが以下のSQLと組み合わせれば簡単に実装できるでしょう。

※サンプルデータは以下を使用


mysql> SELECT id, name, X(latlng) as lng, Y(latlng) as lat, zoom, AsText(latlng) as geomtext FROM spot;
+----+--------------------------+------------+-----------+------+-----------------------------+
| id | name                     | lng        | lat       | zoom | geomtext                    |
+----+--------------------------+------------+-----------+------+-----------------------------+
|  1 | アシアル株式会社         | 139.762522 | 35.706752 |   19 | POINT(139.762522 35.706752) | 
|  2 | 東京ドーム               | 139.752016 | 35.705567 |   18 | POINT(139.752016 35.705567) | 
|  3 | 東京タワー               | 139.745423 | 35.658582 |   18 | POINT(139.745423 35.658582) | 
|  4 | 大阪駅                   |     135.29 |     34.42 |   16 | POINT(135.29 34.42)         | 
|  5 | 名古屋                   |     136.54 |     35.11 |   16 | POINT(136.54 35.11)         | 
|  6 | 那覇市                   |     127.41 |     26.13 |   16 | POINT(127.41 26.13)         | 
+----+--------------------------+------------+-----------+------+-----------------------------+
6 rows in set (0.00 sec)


■2点間の距離の近い順に5件取得する。(ここではアシアルの緯度経度から近い順)


mysql> SELECT 
    -> id, name, X(latlng) as lng, Y(latlng) as lat, zoom, 
    -> GLength(GeomFromText(CONCAT('LineString(139.762522 35.706752,', X(latlng), ' ', Y(latlng),')'))) AS len 
    -> FROM spot ORDER BY len;
+----+--------------------------+------------+-----------+------+-------------------+
| id | name                     | lng        | lat       | zoom | len               |
+----+--------------------------+------------+-----------+------+-------------------+
|  1 | アシアル株式会社         | 139.762522 | 35.706752 |   19 |                 0 | 
|  2 | 東京ドーム               | 139.752016 | 35.705567 |   18 | 0.010572618455228 | 
|  3 | 東京タワー               | 139.745423 | 35.658582 |   18 | 0.051114818800422 | 
|  5 | 名古屋                   |     136.54 |     35.11 |   16 |   3.2773100234778 | 
|  4 | 大阪駅                   |     135.29 |     34.42 |   16 |   4.6539428176534 | 
|  6 | 那覇市                   |     127.41 |     26.13 |   16 |    15.63006649474 | 
+----+--------------------------+------------+-----------+------+-------------------+
6 rows in set (0.00 sec)


■指定した範囲内のデータを取得する。(ここでは東京周辺の範囲のみ)


mysql> SELECT id, name, X(latlng) as lng, Y(latlng) as lat, zoom 
    -> FROM spot 
    -> WHERE MBRContains(GeomFromText('LineString(140.05508422851562 36.00134056648952, 139.20089721679688 35.55345722493522)'), latlng);
+----+--------------------------+------------+-----------+------+
| id | name                     | lng        | lat       | zoom |
+----+--------------------------+------------+-----------+------+
|  1 | アシアル株式会社         | 139.762522 | 35.706752 |   19 | 
|  2 | 東京ドーム               | 139.752016 | 35.705567 |   18 | 
|  3 | 東京タワー               | 139.745423 | 35.658582 |   18 | 
+----+--------------------------+------------+-----------+------+
3 rows in set (0.00 sec)


このように、通常のカラム型で保存した場合と違い、位置情報を有効に使用することができます。
まだ、2つのPOINT間の最短距離を返してくれる、Distanceなどの関数は使えないようですが、
マニュアルを見る限りでは、将来的にはサポートされるようです。

パフォーマンス等については、まだ私のほうでは未検証ですが、
位置情報を扱うには非常に簡単に扱えますので、ぜひ試してみてはいかがでしょう。

[補足]PostgreSQLでも位置情報を扱うことができ、PostGISやPostLBSなどのさらに便利な感じのものもあります。