web-dev-qa-db-ja.com

MySQLの隠された機能

私は Microsoft SQL Server を長年使用してきましたが、ごく最近になってWebアプリケーションで MySQL を使用し始めたばかりで、知識に飢えています。

"hidden feature" question の長い行を続けるために、MySQLの隠された機能や便利な機能を知りたいと思います。

101
GateKiller

あなたが賞金をかけたので、私は私の苦労して獲得した秘密を共有します...

一般に、今日調整したすべてのSQLは、サブクエリを使用する必要がありました。 Oracleデータベースの世界から来たので、当たり前のことはMySQLでも同じようには機能しませんでした。また、MySQLのチューニングに関する私の読書は、MySQLがクエリの最適化に関してOracleの背後にあると結論付けています。

ほとんどのB2Cアプリケーションに必要な単純なクエリはMySQLで適切に機能しますが、インテリジェンスレポートに必要な集計レポートタイプのクエリのほとんどは、MySQLがそれらをより速く実行するようにSQLクエリをかなり計画し、再編成する必要があります。

管理:

max_connectionsは、同時接続の数です。デフォルト値は100接続(5.0以降151)-非常に小さいです。

注意:

接続はメモリを消費し、OSは多くの接続を処理できない場合があります。

Linux/x86用のMySQLバイナリを使用すると、最大4096の同時接続が可能になりますが、多くの場合、自己コンパイルされたバイナリには制限がありません。

開いているテーブルと同時接続の数に合わせてtable_cacheを設定します。 open_tablesの値に注意してください。値が急速に大きくなる場合は、サイズを増やす必要があります。

注意:

前述の2つのパラメーターには、多くの開いているファイルが必要な場合があります。 20 + max_connections + table_cache * 2は、必要なものの適切な推定値です。 Linux上のMySQLにはopen_file_limitオプションがあり、この制限を設定します。

複雑なクエリがある場合、sort_buffer_sizeとtmp_table_sizeは非常に重要です。値はクエリの複雑さと使用可能なリソースに依存しますが、開始点として推奨されるのはそれぞれ4Mbと32Mbです。

注:これらは、read_buffer_size、read_rnd_buffer_sizeなどの「接続ごとの」値です。つまり、この値は各接続に必要な場合があります。したがって、これらのパラメーターを設定するときは、負荷と使用可能なリソースを考慮してください。たとえば、sort_buffer_sizeは、MySQLがソートを行う必要がある場合にのみ割り当てられます。注:メモリが不足しないように注意してください。

多くの接続が確立されている場合(つまり、永続的な接続のないWebサイト)、thread_cache_sizeをゼロ以外の値に設定することでパフォーマンスを改善できる場合があります。 16は最初から良い値です。 threads_createdが急速に大きくならないまで値を増やします。

主キー:

AUTO_INCREMENTカラムはテーブルごとに1つだけ存在でき、インデックスを作成する必要があり、DEFAULT値を持つことはできません

KEYは通常、INDEXの同義語です。キー属性PRIMARY KEYは、列定義で指定される場合、単なるKEYとして指定することもできます。これは、他のデータベースシステムとの互換性のために実装されました。

PRIMARY KEYは、すべてのキー列をNOT NULLとして定義する必要がある一意のインデックスです

PRIMARY KEYまたはUNIQUEインデックスが整数型の1つの列のみで構成されている場合、SELECTステートメントでその列を「_rowid」として参照することもできます。

MySQLでは、PRIMARY KEYの名前はPRIMARYです

現在、InnoDB(v5.1?)テーブルのみが外部キーをサポートしています。

通常、テーブルを作成するときに必要なすべてのインデックスを作成します。 PRIMARY KEY、KEY、UNIQUE、またはINDEXとして宣言された列はすべてインデックス付けされます。

NULLは「値を持たない」ことを意味します。 NULLをテストするには、cannot=、<、または<>などの算術比較演算子を使用します。代わりにIS NULLおよびIS NOT NULL演算子を使用します。

NO_AUTO_VALUE_ON_ZEROは、次のシーケンス番号をNULLのみが生成するように、0の自動インクリメントを抑制します。このモードは、テーブルのAUTO_INCREMENTカラムに0が保存されている場合に役立ちます。 (ちなみに、0を保存することはお勧めできません。)

新しい行に使用されるAUTO_INCREMENTカウンターの値を変更するには:

ALTER TABLE mytable AUTO_INCREMENT = value; 

またはSET INSERT_ID = value;

特に指定がない限り、値は1000000で始まるか、次のように指定します。

...)ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 1

タイムスタンプ:

TIMESTAMP列の値は、保存のために現在のタイムゾーンからUTCに変換され、取得のためにUTCから現在のタイムゾーンに変換されます。

http://dev.mysql.com/doc/refman/5.1/en/timestamp.html テーブル内の1つのTIMESTAMP列に対して、現在のタイムスタンプをデフォルト値として割り当て、自動値を更新します。

wHERE句でこれらのタイプのいずれかを使用する場合、注意が必要なことの1つは、WHERE UNIX_TIMESTAMP(datecolumn)= 1057941242ではなくWHERE datecolumn = FROM_UNIXTIME(1057941242)を実行することです。その列に。

http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

 UNIX_TIMESTAMP() 
 FROM_UNIXTIME() 
 UTC_DATE()
 UTC_TIME()
 UTC_TIMESTAMP()

mySQLで日時をUNIXタイムスタンプに変換する場合:
次に、24時間を追加します。

ここで何が起こっているのかです。 UNIXタイムスタンプを日時に変換するとき、タイムゾーンが考慮されます。2006年10月28日から29日までは、夏時間から1時間遅れました。

MySQL 4.1.3以降、CURRENT_TIMESTAMP()、CURRENT_TIME()、CURRENT_DATE()、およびFROM_UNIXTIME()関数は、接続の現在のタイムゾーン、time_zoneシステム変数の値として使用可能です。さらに、UNIX_TIMESTAMP()は、引数が現在のタイムゾーンの日時値であることを前提としています。

現在のタイムゾーン設定は、UTC_TIMESTAMP()などの関数によって表示される値や、DATE、TIME、DATETIME列の値には影響しません。

注:ON UPDATE[〜#〜] only [〜#〜]は、フィールドが変更された場合にDateTimeを更新しますその後、DateTimeは更新されません!

さらに、最初のTIMESTAMPは、指定されていない場合でもデフォルトで常にAUTOUPDATEです

Datesを使用する場合、データ数学は整数と、同じ理由で真夜中からの秒を追加または減算するだけの簡単な問題なので、私はほとんど常にJulian Dateに夢中になります。秒よりも細かい粒度の時間を必要とすることはまれです。

これらは両方とも4バイト整数として格納でき、スペースが非常に狭い場合は、2106年頃まで有効な符号なし整数としてUNIX時間(エポック1/1/1からの秒数)に結合できます。

'24時間の秒= 86400

'符号付き整数max val = 2,147,483,647-68年の秒を保持できます

'符号なし整数の最大値= 4,294,967,295-136年の秒を保持できます

バイナリプロトコル:

MySQL 4.1では、文字列形式との間で変換せずに非文字列データ値をネイティブ形式で送受信できるバイナリプロトコルが導入されました。 (非常に便利)

それ以外に、mysql_real_query()はmysql_query()よりも高速です。これは、strlen()を呼び出してステートメント文字列を操作しないためです。

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html バイナリプロトコルは、サーバー側の準備済みステートメントをサポートし、ネイティブ形式でのデータ値の送信を許可します。 MySQL 4.1の以前のリリースでは、バイナリプロトコルにかなりの修正が加えられました。

IS_NUM()マクロを使用して、フィールドに数値型があるかどうかをテストできます。タイプ値をIS_NUM()に渡すと、フィールドが数値の場合にTRUEと評価されます。

注意すべきことの1つは、バイナリデータ[〜#〜] [〜#〜](-#=]をエスケープしてMySQLを覚えている場合、通常のクエリ内で送信できることです。 onlyには、バックスラッシュと引用文字をエスケープする必要があります。これは、たとえば暗号化/ソルトパスワードなどの短いバイナリ文字列を挿入するための非常に簡単な方法です。

マスターサーバー:

http://www.experts-exchange.com/Database/MySQL/Q_22967482.html

http://www.databasejournal.com/features/mysql/article.php/10897_3355201_2

GRANT REPLICATION SLAVE ONto slave_user IDENTIFIED BY 'slave_password'

#Master Binary Logging Config  STATEMENT causes replication 
              to be statement-based -  default

log-bin=Mike
binlog-format=STATEMENT
server-id=1            
max_binlog_size = 10M
expire_logs_days = 120    


#Slave Config
master-Host=master-hostname
master-user=slave-user
master-password=slave-password
server-id=2

バイナリログファイルは以下を読む必要があります:

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://www.mydigitallife.info/2007/10/06/how-to-read-mysql-binary-log-files-binlog-with-mysqlbinlog/

http://dev.mysql.com/doc/refman/5.1/en/mysqlbinlog.html

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://dev.mysql.com/doc/refman/5.1/en/binary-log-setting.html

RESET MASTERステートメントを使用してすべてのバイナリログファイルを削除するか、PURGE MASTERを使用してそれらのサブセットを削除できます。

--result-file = binlog.txt TrustedFriend-bin.000030

正規化:

http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html

UDF関数

http://www.koders.com/cpp/fid10666379322B54AD41AEB0E4100D87C8CDDF1D8C.aspx

http://souptonuts.sourceforge.net/readme_mysql.htm

データ型:

http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html

http://www.informit.com/articles/article.aspx?p=1238838&seqNum=2

http://bitfilm.net/2008/03/24/saving-bytes-efficient-data-storage-mysql-part-1/

注意すべきことの1つは、CHARとVARCHARの両方を持つ混合テーブルでは、mySQLがCHARをVARCHARに変更することです。

RecNum integer_type UNSIGNED NOT NULL AUTO_INCREMENT、PRIMARY KEY(RecNum)

MySQLは、標準SQLおよびISO 8601仕様に従って、常に年を最初に日付を表​​します

その他:

一部のMySQl機能をオフにすると、データファイルが小さくなり、アクセスが高速になります。例えば:

--datadirはデータディレクトリを指定し、

--skip-innodbは、innoオプションをオフにして10-20M節約します

詳細はこちら http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

ダウンロードChapter 7-無料

InnoDBはトランザクション処理ですが、それに伴うパフォーマンスのオーバーヘッドがあります。 MyISAMテーブルは、プロジェクトの90%に十分であることがわかりました。非トランザクションセーフテーブル(MyISAM)には独自の利点がいくつかありますが、それらはすべて次の理由で発生します。

トランザクションのオーバーヘッドはありません。

はるかに高速

より少ないディスク容量要件

更新の実行に必要なメモリが少ない

各MyISAMテーブルは、ディスク上の3つのファイルに保存されます。ファイルの名前はテーブル名で始まり、ファイルの種類を示す拡張子が付いています。 .frmファイルにはテーブル形式が保存されます。データファイルの拡張子は.MYD(MYData)です。インデックスファイルの拡張子は.MYI(MYIndex)です。

これらのファイル保管場所にそのままコピーできます。時間のかかるMySQL Administratorsバックアップ機能を使用せずに(復元も)

秘Theは、これらのファイルのコピーを作成してからテーブルを削除することです。ファイルを戻すと、MySQlはそれらを認識し、テーブルトラッキングを更新します。

バックアップ/復元が必要な場合、

バックアップの復元、または既存のダンプファイルからのインポートは、各テーブルにあるインデックスとプライマリキーの数によっては時間がかかる場合があります。元のダンプファイルを次のように囲むことで変更することにより、このプロセスを劇的に高速化できます。

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;

再ロードの速度を大幅に上げるには、SQLコマンドSET AUTOCOMMIT = 0;を追加します。ダンプファイルの先頭に、COMMITを追加します。最後までコマンド。

デフォルトでは、自動コミットはオンになっています。つまり、ダンプファイル内のすべての挿入コマンドは個別のトランザクションとして扱われ、次のトランザクションが開始される前にディスクに書き込まれます。これらのコマンドを追加しないと、大きなデータベースをInnoDBにリロードするのに何時間もかかることがあります...

MySQLテーブルの行の最大サイズは65,535バイトです

MySQL 5.0.3以降のVARCHARの有効な最大長=最大行サイズ(65,535バイト)

VARCHAR値は、保管時に埋め込まれません。標準SQLに準拠して、値が格納および取得されるときに、末尾のスペースが保持されます。

MySQLのCHAR値とVARCHAR値は、末尾のスペースに関係なく比較されます。

CHARを使用すると、レコード全体が固定サイズの場合にのみアクセスが高速化されます。つまり、可変サイズのオブジェクトを使用する場合、すべてを可変サイズにすることもできます。 VARCHARも含むテーブルでCHARを使用しても速度は上がりません。

MySQL 5.0.3では、255文字のVARCHAR制限が65535文字に引き上げられました。

全文検索はMyISAMテーブルでのみサポートされています。

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

BLOB列には文字セットがなく、ソートと比較は列値のバイトの数値に基づいています

厳密なSQLモードが有効になっておらず、列の最大長を超える値をBLOBまたはTEXT列に割り当てると、値が収まるように切り捨てられ、警告が生成されます。

便利なコマンド:

厳格モードを確認します:SELECT @@ global.sql_mode;

厳格モードをオフにします。

SET @@ global.sql_mode = '';

SET @@ global.sql_mode = 'MYSQL40'

または削除:sql-mode = "STRICT_TRANS_TABLES、...

mytableの列を表示

SELECT max(namecount)AS virtualcolumn FROM mytable ORDER BY virtualcolumn

http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-fields.html

http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_last-insert-id last_insert_id()

現在のスレッドに挿入された最後の行のPKを取得しますmax(pkcolname)全体で最後のPKを取得します。

注:テーブルが空の場合、max(pkcolname)は1を返します。mysql_insert_id()は、ネイティブMySQL C API関数mysql_insert_id()の戻り値の型をlong型(PHPではintという名前)に変換します。

AUTO_INCREMENTカラムのカラムタイプがBIGINTの場合、mysql_insert_id()によって返される値は正しくありません。代わりに、SQLクエリで内部MySQL SQL関数LAST_INSERT_ID()を使用します。

http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id

テーブルにデータを挿入しようとするとエラーが発生することに注意してください:

Unknown column ‘the first bit of data what you want to put into the table‘ in ‘field list’

のようなものを使用して

INSERT INTO table (this, that) VALUES ($this, $that)

テーブルに固定しようとしている値の周りにアポストロフィがないためです。したがって、コードを次のように変更する必要があります。

INSERT INTO table (this, that) VALUES ('$this', '$that') 

値ではなく、MySQLフィールド、データベース、またはテーブルを定義するために使用されることを思い出してください;)

クエリ中にサーバーへの接続が失われました:

http://dev.mysql.com/doc/refman/5.1/en/gone-away.html

http://dev.mysql.com/doc/refman/5.1/en/packet-too-large.html

http://dev.mysql.com/doc/refman/5.0/en/server-parameters.html

http://dev.mysql.com/doc/refman/5.1/en/show-variables.html

http://dev.mysql.com/doc/refman/5.1/en/option-files.html

http://dev.mysql.com/doc/refman/5.1/en/error-log.html

クエリのチューニング

http://www.artfulsoftware.com/infotree/queries.php?&bw=131

まあそれは私が思うにボーナスを獲得するのに十分でなければなりません...素晴らしいfreeデータベースを持つ多くの時間と多くのプロジェクトの成果。主にMySQLを使用して、Windowsプラットフォームでアプリケーションデータサーバーを開発しています。私が真っ直ぐにしなければならなかった最悪の混乱は

究極のMySQLレガシーデータベースの悪夢

これには、ここで説明した多くのトリックを使用して、テーブルを有用なものに処理するための一連のアプリケーションが必要でした。

これが驚くほど役に立つと思ったら、投票して感謝を表明してください。

また、www.coastrd.comにある他の記事やホワイトペーパーもご覧ください。

161
Mike Trader

MySQLのそれほど隠されていない機能の1つは、SQLに準拠するのがあまり得意ではないことです。まあ、実際にはバグではなく、もっと gotchas ... :-)

22
mat

現在キャッシュにあるテーブルを調べるコマンド:

mysql> SHOW open TABLES FROM test;
+----------+-------+--------+-------------+
| DATABASE | TABLE | In_use | Name_locked |
+----------+-------+--------+-------------+
| test     | a     |      3 |           0 |
+----------+-------+--------+-------------+
1 row IN SET (0.00 sec)

MySQLパフォーマンスブログ から)

21
Eran Galperin

誰が何をしているのかを調べるコマンド:

mysql> show processlist;
show processlist;
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
| Id | User        | Host            | db   | Command | Time | State                            | Info             |
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
|  1 | root        | localhost:32893 | NULL | Sleep   |    0 |                                  | NULL             |
|  5 | system user |                 | NULL | Connect |   98 | Waiting for master to send event | NULL             |
|  6 | system user |                 | NULL | Connect | 5018 | Reading event from the relay log | NULL             |
+-----+------+-----------+---------+---------+-------+-------+------------------+
3 rows in set (0.00 sec) 

そして、あなたはプロセスを殺すことができます:

mysql>kill 5 
15
CMS

inet_ntoa()およびinet_aton()に対するMySQLの組み込みサポートが特に気に入っています。テーブル内のIPアドレスの処理が非常に簡単になります(少なくともIPv4アドレスのみである限り!)

11
Alnitak

私は愛してる - on duplicate key (別名アップサート、マージ)遅延的に作成されたすべての種類のカウンター:

insert into occurances(Word,count) values('foo',1),('bar',1) 
  on duplicate key cnt=cnt+1

1つのクエリに多数の行を挿入し、各行の重複したインデックスをすぐに処理できます。

11
Kornel

クライアントの「ポケットベル」コマンド

たとえば、結果に10,000行があり、それらを表示したい場合(これは、通常はLinuxでのWindowsのYMMVの場合のように、「less」コマンドと「tee」コマンドが使用可能であることを前提としています)

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

また、「少ない」ファイルビューアでそれらを取得するので、それらをうまくページングしたり、検索したりできます。

また

pager tee myfile.txt
select a_few_things FROM tbl WHERE i_want_to_save_output_to_a_file;

便利にファイルに書き込みます。

7
MarkR

あなたが面白いと思うかもしれないいくつかのこと:

<query>\G -- \G in the CLI instead of the ; will show one column per row
explain <query>; -- this will show the execution plan for the query
6
SorinV

非表示の機能ではありませんが、それでも便利です。 http://mtop.sourceforge.net/

4
Eddy

これはMySQL固有ではないと思いますが、私にとって啓発的なものです。

書く代わりに

WHERE (x.id > y.id) OR (x.id = y.id AND x.f2 > y.f2) 

あなたはただ書くことができます

WHERE (x.id, x.f2) > (y.id, y.f2)
3
Johan

ここに私のヒントのいくつかがあります-私は私のブログでそれらについてブログに書きました( Link

  1. 変数を宣言するときに「@」記号を使用する必要はありません。
  2. ステートメントの終わりを区切るには、区切り文字(デフォルトは ';')を使用する必要があります- Link
  3. MS-SQL 2005とmySQLの間でデータを移動しようとすると、いくつかの問題が発生します- Link
  4. MySQLで大文字と小文字を区別する一致を行う- link
3
Nikhil

大規模または高トランザクションのInnoDbデータベースを使用して「INNODBステータスを表示」 Mysqlパフォーマンスブログ を学習および理解する場合、それはあなたの友達になります。

3
Hawk Kroeger

組み込みの SQLプロファイラー

2
Eugene Yarmash

実際には 文書化された ですが、非常に迷惑です:誤った日付やその他の誤った入力に対する自動変換。

MySQL 5.0.2より前では、MySQLは違法または不適切なデータ値を許容しており、データ入力の正当な値に強制します。 MySQL 5.0.2以降では、デフォルトの動作のままですが、サーバーのSQLモードを変更して、サーバーがそれらを拒否し、発生したステートメントを中止するように、より伝統的な不良値の処理を選択できます。

日付に関して:MySQLが入力を近くの有効な日付に調整せず、代わりに0000-00-00定義上無効です。ただし、その場合でも、この値をサイレントに保存するのではなく、MySQLに障害が発生する可能性があります。

2
Arjan

mysqlsla-非常によく使用されるスロークエリログ分析ツールの1つ。 uは最後にスロークエリログを公開してから、最悪のクエリのトップ10を見ることができます。また、BADクエリが起動された回数と、サーバーでかかった合計時間も知ることができます。

2
pawan

大規模なデータセットとDATETIMEフィールドを使用したベンチマーク中、このクエリを実行するのは常に遅くなります。

SELECT * FROM mytable
WHERE date(date_colum) BETWEEN '2011-01-01' AND ''2011-03-03';

このアプローチより:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'
1
Osvaldo Mercado

デフォルトでは、InnoDBはすべてのテーブルを1つのグローバルテーブルスペースに格納します。グローバルテーブルスペースは決して縮小しません

innodb_file_per_tableを使用すると、テーブルまたはデータベースを削除したときに削除される個別のテーブルスペースに各テーブルを配置できます。

それ以外の場合はスペースを再利用するためにデータベースをダンプおよび復元する必要があるため、事前に計画してください。

テーブルごとのテーブルスペースを使用

1
serbaut

日時列に空の文字列値 ""を挿入すると、MySQLは値を00/00/0000 00:00:00として保持します。 null値を保存するOracleとは異なります。

1
Devid G