Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
OracleよりもMySQLの方が便利だと思うSQL構文比較 | スマホアプリ開発記

スマホアプリ開発記

スマホアプリやサービス作りで感じたことを書いています。

オラクルを辞めて半年間MySQLを使って感じたこと。

パフォーマンスチューニング、運用管理、バックアップリカバリ等はOracleの方が遥かに優れていますが、こと単にSQL文の構文に注目すると、コミュニティが使いやすく育てているからでしょうか、Oracleと比較して便利だなと思うことがいくつかあります。MySQLはいかに簡単に使えるかに一つの主眼が置かれてる気がします。

※SQLを確認したバージョンはOracle 10g R2とMySQL5.0です。少し古くてごめんなさい。

■ 1. dual表に問い合わせなくていい

ちょっとしたSQLを打ちたいときに、速い。てか、dual表って何だよって感じですよね。これは、MySQLの方が直観的だと思う。

Oracle
SQL> select sysdate from dual;

SYSDATE
---------
18-AUG-10

MySQL
mysql> select sysdate();
+---------------------+
| sysdate() |
+---------------------+
| 2010-08-18 23:11:27 |
+---------------------+
1 row in set (0.00 sec)

■ 2. シーケンス作らなくていい

表の列にauto_increment属性をつけることで、insert時に勝手に採番してくれる。単に固有のID番号を振りたい時は便利すぎる。何でOracleにはないんだ?ってくらい。テーブルごとにシーケンス作って管理するのって結構めんどうくさい。
ただ、性能面で言うと、仕組み的に管理テーブルの行ロックを取ってしまうはずなので、OracleのSEQUENCEには全く敵わないでしょう。後は、複数テーブルに同じ番号を振りたいときも困る。

■ 3.一列一行表示ができる

これは、SQLではなくコマンドライン・ユーティリティの機能ですが、列数が多い表を問い合わせる時に表示方式をSQLの末端のみで変えられるのは便利。列数が多いときに表形式の表示だと、表示が崩れてすごく見にくい。OracleのSQL Plusだと、文字列型は定義された文字数分列幅が取られるので、set col forとかset pagesとかを一々やらないといけない。

Oracle
気を抜くとすぐにこんな事態になる。
SQL> select * from city;

ID
----------
NAME
--------------------------------------------------------------------------------
COUNTRYCODE
--------------------------------------------------------------------------------
DISTRICT
--------------------------------------------------------------------------------
POPULATION
----------
1
Kabul
AFG

ID
----------
NAME
--------------------------------------------------------------------------------
COUNTRYCODE
--------------------------------------------------------------------------------
DISTRICT
--------------------------------------------------------------------------------
POPULATION
----------
Kabol
1780000

MySQL
mysql> select * from City;
+----+----------+-------------+----------+------------+
| ID | Name | CountryCode | District | Population |
+----+----------+-------------+----------+------------+
| 1 | Kabul | AFG | Kabol | 1780000 |
| 2 | Qandahar | AFG | Qandahar | 237500 |
| 3 | Herat | AFG | Herat | 186800 |
| 4 | Tokyo | JPN | Tokyo | 20000000 |
+----+----------+-------------+----------+------------+
4 rows in set (0.01 sec)

mysql> select * from City\G
*************************** 1. row ***************************
ID: 1
Name: Kabul
CountryCode: AFG
District: Kabol
Population: 1780000
*************************** 2. row ***************************
ID: 2
Name: Qandahar
CountryCode: AFG
District: Qandahar
Population: 237500
*************************** 3. row ***************************
ID: 3
Name: Herat
CountryCode: AFG
District: Herat
Population: 186800
*************************** 4. row ***************************
ID: 4
Name: Tokyo
CountryCode: JPN
District: Tokyo
Population: 20000000
4 rows in set (0.00 sec)

■ 4. 問い合わせ件数制限がシンプル

問い合わせ件数を制限したいときに、最後にLIMIT nで済むのが便利だし直観的。OracleならROWNUMを使ってWEHRE句で絞る必要がある。ただ、ROWNUMは行番号を示す疑似列として使えるので、単に件数を絞り込むLIMIT句よりも柔軟性は高い。

Oracle
SQL> select * from ciry where rownum < 2;

ID NAME COU DISTRICT POPULATION
---------- ---------- --- ---------- ----------
1 Kabul AFG Kabol 1780000

MySQL
mysql> select * from City limit 1;
+----+-------+-------------+----------+------------+
| ID | Name | CountryCode | District | Population |
+----+-------+-------------+----------+------------+
| 1 | Kabul | AFG | Kabol | 1780000 |
+----+-------+-------------+----------+------------+
1 row in set (0.00 sec)

■ 5. group by に列番号を指定できる

MySQLはgroup byに列番号を指定することができる。Oracleは、order byであれば列番号指定ができるが、group byは明示的に列名を指定しなくてはいけない。

Oracle
SQL> select countrycode, count(*) from City group by 1;
select countrycode, count(*) from City group by 1
*
ERROR at line 1:
ORA-00979: not a GROUP BY expression

SQL> select countrycode, count(*) from City group by countrycode;

COU COUNT(*)
--- ----------
JPN 1
AFG 3

MySQL
mysql> select countrycode, count(*) from City group by 1;
+-------------+----------+
| countrycode | count(*) |
+-------------+----------+
| AFG | 3 |
| JPN | 1 |
+-------------+----------+
2 row in set (0.00 sec)

これならまだ列名入れればいいじゃんってだけの違いですが、列に計算結果などを使っていると変わってくる。
例えば、適当な例ですが、先頭文字で集計する場合。

Oracle
列番号も列別名も使えない。同じ列の記述を二か所に書く必要があり、かっこ悪い。どうしてもスマートにしたいならサブクエリ使うしかない。
SQL> select substr(CountryCode,1,1) init, count(*) from City group by 1;
select substr(CountryCode,1,1) init, count(*) from City group by 1
*
ERROR at line 1:
ORA-00979: not a GROUP BY expression


SQL> select substr(CountryCode,1,1) init, count(*) from City group by init;
select substr(CountryCode,1,1) init, count(*) from City group by init
*
ERROR at line 1:
ORA-00904: "INIT": invalid identifier

SQL> select substr(CountryCode,1,1) init, count(*) from City group by substr(CountryCode,1,1);

IN COUNT(*)
-- ----------
A 3
J 1

MySQL
列番号も列別名も指定できる。
mysql> select substr(CountryCode,1,1) init, count(*) from City group by 1;
+------+----------+
| init | count(*) |
+------+----------+
| A | 3 |
| J | 1 |
+------+----------+
2 rows in set (0.00 sec)

mysql> select substr(CountryCode,1,1) init, count(*) from City group by init;
+------+----------+
| init | count(*) |
+------+----------+
| A | 3 |
| J | 1 |
+------+----------+
2 rows in set (0.00 sec)

mysql> select substr(CountryCode,1,1) init, count(*) from City group by substr(CountryCode,1,1);
+------+----------+
| init | count(*) |
+------+----------+
| A | 3 |
| J | 1 |
+------+----------+
2 rows in set (0.00 sec)

■ 6. SQLでCSV 出力できる

最高に便利だと思うのがこれかも。Oracle 在籍時代、何度も顧客に聞かれたことの一つ。そして、何でCSV出力すらできないの?と責め立てられたことの一つ。Oracleは表データをCSV出力できる機能をそれ自身に持っていない。そのため、CSV出力するためだけにサードパーティ製アンロードツールが売れたり。
Oracleの機能でやろうとすると、SQL Plusでごりごりと出力の形式を調整するスクリプトを書く必要がある。ツール依存なので、汎用性がない。ダブルクオテーションくくりとか考え出すと死ねる。

MySQLだと、これだけ。

MySQL
mysql> select * from City into outfile "/tmp/City.csv"
-> fields terminated by ',' enclosed by '"' lines terminated by '\r\n';