innodb_buffer_pool_size デフォルト値 : 128M
innodb_buffer_pool_size = 128M
MySQLのみが稼働する専用のサーバーでInnoDBのみを利用している場合メインメモリの50~75%程度を割り当てると言われていたり、
また、AWS RDSでMySQLを使用する場合のデフォルト値はメインメモリの3/4に設定されています。
設定例 いわゆるvpsでDB以外にも色々サーバが入っているメモリ4Gマシンの場合 ( 50%を割り当てます)
[mysqld]
innodb_buffer_pool_size = 2G
確認方法
SELECT @@innodb_buffer_pool_size/1024/1024;
設定値の結果が MB で返ってきます
引用 : https://tinyurl.com/24qp3uuz
参考 : https://qiita.com/fururun02/items/e143ae87ec8a1c3884eb
[mysqld]
innodb_dedicated_server=ON
innodb_dedicated_serverは、MySQL8.0.3で追加されたシステム変数です。
この設定をONにすることで、以下の4つのシステム変数を自動で設定します。
innodb_buffer_pool_size
innodb_log_file_size
innodb_log_files_in_group
innodb_flush_method
引用 : https://tinyurl.com/25ovhkkj
引用元 : MySQL8.0ではGRANT構文でユーザを作成できない – guro_chanの手帳
grant all on *.* to 'guro'@'localhost' identified by 'avava' with grant option;
↓
create user 'guro'@'localhost' identified by 'avava';
grant all on *.* to 'guro'@'localhost' with grant option;
flush privileges;
例えば、customersテーブルでcity列が'New York'の顧客のstateを'NY'に更新する場合、次のクエリを使用できます。
UPDATE customers
SET state = 'NY'
WHERE city = 'New York';
show databases;
SELECT user, host FROM mysql.user;
SHOW GRANTS FOR 'myuser'@'%';
https://dev.mysql.com/doc/refman/8.0/en/show-grants.html
SELECT User FROM mysql.db WHERE db ="my-database";
GRANT ALL PRIVILEGES ON `mydb`.* TO `myuser`@`%`;
mysql (mariaDB)起動時
systemctl start mysql
以下のようなエラーが返ってきてMySQLを起動できない時があります
Job for mariadb.service failed because the control process exited with error code. See "systemctl status mariadb.service" and "journalctl -xe" for details.
cat /etc/my.cnf.d/server.cnf | grep error
ログの場所が分かります ↓
log-error = /var/log/mysql/mysqld.log
cat /var/log/mysql/mysqld.log
以下のように [ERROR] となっている箇所を探します
2021-10-14 12:26:52 139785906096384 [ERROR] mysqld: File '/var/lib/mysql/aria_log.00000006' not found (Errcode: 2 "No such file or directory")
2021-10-14 12:26:52 139785906096384 [ERROR] mysqld: Aria engine: log initialization failed
2021-10-14 12:26:52 139785906096384 [ERROR] Plugin 'Aria' init function returned error.
2021-10-14 12:26:52 139785906096384 [ERROR] Plugin 'Aria' registration as a STORAGE ENGINE failed.
2021-10-14 12:49:25 139975498930432 [ERROR] mysqld: Aria engine: log data error
last_log_page: (6,0x0) is less than
checkpoint page: (7,0x2000)
2021-10-14 12:49:25 139975498930432 [ERROR] mysqld: Aria engine: log initialization failed
上記のエラーメッセージの場合は aria_log.xxxxxx でエラーが出ているので、ログファイルを全削除します。 これで再起動すれば無事起動します。
それは文字数オーバーのエラーです以下の文字数を超える場合に表示されるのってデータベースのカラム設計を見直しましょう。
TINYBLOB, TINYTEXT L 255 Byte
BLOB, TEXT (64 KB)
MEDIUMBLOB, MEDIUMTEXT (16 MB)
LONGBLOB, LONGTEXT (4 GB)
最小マッチ文字を2文字にセットする
[mysqld]
innodb_ft_min_token_size=2
ft_min_word_len=2
ALTER TABLE `テーブル名` ADD FULLTEXT(`カラム名`);
通常の検索 LIKE検索(遅い)
SELECT item_name AS `numrows`
FROM `item_dt`
WHERE
`item_name` LIKE '%SSD256GB%';
全文検索(速い)
SELECT item_name AS `numrows`
FROM `item_dt`
WHERE
MATCH(`item_name`) AGAINST( "+SSD256GB" IN BOOLEAN MODE);
インデックスを削除 → インデックスを再度作成 を行ないます。
show index from 【テーブル名】;
DROP INDEX 【インデックス名】 ON 【テーブル名】;
ALTER TABLE `テーブル名` ADD FULLTEXT(`カラム名`);
SELECT
*
FROM my_table
ORDER BY
salesrank_no is null, salesrank_no LIMIT 10;
↓ 別々で取得して、UNION を使用します。
(SELECT * FROM my_table ORDER BY salesrank_no is null, salesrank_no LIMIT 10)
UNION ALL
(SELECT * FROM my_table WHERE AND ( salesrank_no is null ) LIMIT 10)
ORDER BY salesrank_no is null, salesrank_no LIMIT 10;
MySQL( MariaDB )の代表的なデータベースエンジンには次のようなものがあります
・MyISAM「MySQLが最初に持っていたデータベースエンジン。トランザクションがないかわりに高速です。ただし現在では使用しません。後継
のAriaを使用しましょう。」
・Aria「MyISAMの改良版。トランザクションが必要ないときはこちらを選択すると良いでしょう」
・InnoDB 「トランザクションが必要な場合はInnoDBを選択します」
use information_schema;
select table_schema, table_name, engine from tables;
use information_schema;
select table_schema, table_name, engine from tables where table_schema = 'my_db' ;
search_dt を【Aria】エンジンで作成する例
DROP TABLE IF EXISTS `search_dt`;
CREATE TABLE `search_dt` (
`search_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`search_name` text,
`search_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`search_id`)
) ENGINE=Aria AUTO_INCREMENT=2824 DEFAULT CHARSET=utf8;
pre.sql で次の内容を保存
SET @OLD_AUTOCOMMIT=@@AUTOCOMMIT, AUTOCOMMIT = 0;
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS = 0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS = 0;
post.sql で次の内容を保存
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
SET AUTOCOMMIT = @OLD_AUTOCOMMIT;
COMMIT;
1. pre.sql
2. dump.sql (実行したいSQL文)
3. post.sql
を連続で実行します。
cat pre.sql dump.sql post.sql | mysql -A -u【ユーザー名】 -p 【DB名】
mysql -uユーザー名 -p データベース名 < SQLファイル名
とするとエラーとなる時の対処法
mysql --help | grep my.cnf
vi /etc/my.cnf
[mysqld]
max_allowed_packet=32M
service mysql restart
mysql -u USER-NAME -p DB-NAME --max_allowed_packet=256M < dump.sql
● 1. MySQLのsql_modeを確認し保存する
phpMyAdmin の 「SQL」から次のSQLを実行し、設定値を保存しておきます。 (何も表示されない場合はその旨記録しておきます)
1. sql_mode を確認する
SHOW VARIABLES LIKE "%sql_mode%";
2. グローバルスコープのsql_mode を確認する
SELECT @@global.sql_mode;
3. ローカルスコープのsql_mode を確認する
SELECT @@session.sql_mode;
● 2. MySQLのDBデータを保存する
phpMyAdmin の 「エクスポート」からDBを保存しておきます。
ALTER TABLE
<テーブル名>
ADD <カラム名> <カラム定義>
AFTER <このカラムの後に>
my_table に 次の3つのカラム server_name text , id_name text , password_name を追加します
ALTER TABLE
my_table
ADD password_name VARCHAR(255) COMMENT 'サーバ' AFTER ftp_password_name ,
ADD id_name VARCHAR(255) COMMENT 'ID' AFTER ftp_password_name ,
ADD server_name VARCHAR(255) COMMENT 'パスワード' AFTER ftp_password_name ;
ALTER TABLE
<テーブル名>
MODIFY <カラム名> <カラム定義>
TINYINT
SMALLINT
MEDIUMINT
INT、INTEGER
BIGINT
BOOL、BOOLEAN
DECIMAL、DEC、NUMERIC
FLOAT
DOUBLE
DATE
DATETIME
TIMESTAMP
TIME
YEAR
CHAR
VARCHAR
BINARY
VARBINARY
TINYBLOB
BLOB
MEDIUMBLOB
LONGBLOB
TINYTEXT
TEXT
MEDIUMTEXT
LONGTEXT
ENUM
SET
mysql --help | grep my.cnf
戻り値
order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /Applications/MAMP/conf/my.cnf ~/.my.cnf
2行目に読み込まれる順番に設定ファイルが記述されています。 上記の例だと
/etc/my.cnf
/etc/mysql/my.cnf
/Applications/MAMP/conf/my.cnf
~/.my.cnf
の順にファイルを調査しに行き読み込みます。 順に cat してファイルがなければ、次のファイル、ファイルがあればそれが mysqlの設定ファイルです。
テーブル名を指定して その後ろの --where で WHERE を記述します
mysqldump -u <ユーザー名> <DB名> <テーブル名> -p --where 'user_name IS NOT NULL' > dump.sql
https://www.sequelpro.com/
定番です。Mac用フリーのアプリ。
https://tableplus.com/
Windows用の一部フリーのアプリ。
show variables like '%time_zone%';
SET time_zone = '+09:00';
SELECT * FROM テーブル1
WHERE カラム1 IN (
SELECT
カラム1
FROM
テーブル1
GROUP BY
カラム1
HAVING
COUNT(カラム1) > 1
)
id : root
password : hoge
my_db_01 と my_db_02 のDB構造を比較します
diff <(mysqldump -uroot -phoge my_db_01 -d) <(mysqldump -uroot -phoge my_db_01 -d)
UPDATE
item_table
SET
delete_flg = 1
WHERE
category_id = 43
INSERT INTO `dics` (`id`, `comment`)
VALUES
('my_text_03', 'コメントテスト);
↓ INSERT を REPLACE に書き換えます。
REPLACE INTO `dics` (`id`, `comment`)
VALUES
('my_text_03', 'コメントテスト);
REPLACE は、INSERT とまったく同じように機能します。ただし、テーブル内の古い行に、PRIMARY KEY または UNIQUE インデックスに関して新しい行と同じ値が含まれている場合、その古い行は新しい行が挿入される前に削除されます。セクション13.2.5「INSERT 構文」を参照してください。
↑ この通りのロジックだとまず INSERTしにいって、同一プライマリーキーで登録が既にある場合はDELETEして再度INSERTというロジックでしょうか。
mysql -u root -p -e 'status'
もし Pleskをお使いの場合は
mysql -uadmin -p`sudo cat /etc/psa/.psa.shadow` -e 'status'
結果例
mysql Ver 15.1 Distrib 10.1.36-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 33536
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.1.36-MariaDB MariaDB Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 36 days 16 hours 59 min 3 sec
Threads: 4 Questions: 3939177 Slow queries: 8 Opens: 8496 Flush tables: 1 Open tables: 152 Queries per second avg: 1.242
10.1.36 であることがわかります。
「view_test」というビューを新規作成します
CREATE VIEW
view_test
AS
SELECT id, name from users where is_deleted = 0;
「view_test」というビューを再定義する感じです。 「CREATE VIEW」 →「ALTER VIEW」に変わります
ALTER VIEW
view_test
AS
SELECT id, name from users where is_deleted = 0;
ビュー「view_test」を削除します
DROP VIEW
view_name
SELECT
item_id, MIN(price_no) AS MIN_PRICE_NO
FROM
items
GROUP BY
item_id
SELECT
A.* ,
B.MIN_PRICE_NO
FROM
item_master AS A
LEFT JOIN TMP AS B ON A.id = B.item_id
ここの TMP を (サブクエリ) で置き換えるだけでOKです。
SELECT
A.* ,
B.MIN_PRICE_NO
FROM
item_master AS A
LEFT JOIN TMP AS B ON A.id = B.item_id
↓
SELECT
A.* ,
B.MIN_PRICE_NO
FROM
item_master AS A
LEFT JOIN
(
SELECT
item_id, MIN(price_no) AS MIN_PRICE_NO
FROM
items
GROUP BY
item_id
)
AS B ON A.id = B.item_id
kusanagiの場合
kusanagi addon install mroonga
kusanagiを使ってない場合
こちらに詳しく載っています
http://asuki-yt.hatenablog.jp/entry/2018/04/03/200000
https://dev.mysql.com/doc/refman/5.6/ja/fulltext-fine-tuning.html
単語の最小長と最大長の構成 インデックスが付けられる単語の最小長および最大長は、InnoDB 検索インデックスの場合は innodb_ft_min_token_size および innodb_ft_max_token_size、MyISAM 検索インデックスの場合は ft_min_word_len および ft_max_word_len で定義されます。これらのオプションのいずれかを変更したら、変更を有効にするために FULLTEXT インデックスを再構築してください。たとえば、2 文字の単語を検索可能にするには、オプションファイルに次の行を配置します。
[mysqld]
innodb_ft_min_token_size=2
ft_min_word_len=2
設定ファイル my.cnf を編集する
vi my.cnf
[mysqld]
# innoDBの全文検索 最小文字数
innodb_ft_min_token_size=1
# MyISAMの全文検索 最小文字数
ft_min_word_len=1
mysqlのリスタート
systemctl restart mysql
設定の確認
show variables like '%ft%';
alter table MY-TABLE add fulltext(`COLUMN-NAME`);
show index in MY-TABLE;
ストレージエンジンを変更しなくても一見日本語全文検索ができているように見えますが、 検索文字の前後に半角文字があるデータしかマッチしません。 ストレージエンジンを Mroonga に変更する事で前後に全角文字があるデータもマッチするようになります。
現在のDB(のテーブル)のストレージエンジンを確認する
use information_schema;
select table_schema, table_name, engine from TABLES WHERE table_schema = 'MY-DB';
ストレージエンジンを Mroonga に変更する
use MY-DB
ALTER TABLE `MY-TABLE` ENGINE = Mroonga;
https://dev.mysql.com/doc/refman/5.6/ja/fulltext-search.html
実行モードには下記の4つありますが
IN NATURAL LANGUAGE MODE
IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
IN BOOLEAN MODE
WITH QUERY EXPANSION
これを一番よく使います。
select * from TABLE-NAME where match(COLUMN-NAME) against( '+検索文字' IN BOOLEAN MODE );
select * from TABLE-NAME where match(COLUMN-NAME) against( '電車 バス' IN BOOLEAN MODE );
select * from TABLE-NAME where match(COLUMN-NAME) against( '+京都 +カフェ' IN BOOLEAN MODE );
実データで検証しました
select count(*) from MY-TABLE
+----------+
| count(*) |
+----------+
| 3431394 |
+----------+
340万データを持つテーブルを検索してみます。
・日本語全文検索
select count(*) from MY-TABLE where match(item_name) against( '+キーワード' IN BOOLEAN MODE );
+----------+
| count(*) |
+----------+
| 1451 |
+----------+
1 row in set (0.05 sec)
・LIKE検索
select count(*) from MY-TABLE where item_name like '%キーワード%';
+----------+
| count(*) |
+----------+
| 1451 |
+----------+
1 row in set (26.32 sec)
MySQLで1GBクラスの大きなデータをインポートする時、デフォルトの設定だと「MySQL server has gone away」が出てしまいます。 そこでメモリの設定を変更しましょう。
公式ドキュメント https://dev.mysql.com/doc/refman/5.6/ja/packet-too-large.html
MySQL 5.6 Server およびクライアント間で転送可能なパケットの最大サイズは 1G バイトです。
クライアントとサーバーの両方にそれぞれ max_allowed_packet 変数があるため、大きなパケットを処理する場合は、クライアントとサーバーの両方のこの変数を増やす必要があります
show variables like 'max_allowed_packet';
+--------------------+---------+
| Variable_name | Value |
+--------------------+---------+
| max_allowed_packet | 4194304 |
+--------------------+---------+
1 row in set (0.03 sec)
4MBに設定されています
16M に設定します
vim /etc/my.cnf.d/my.cnf
[mysqld]
max_allowed_packet = 16M
mysqlリスタート
systemctl restart mysql
mysqlへ接続して直接クエリを流しこみます
set global max_allowed_packet=16777216;
mysql -u USER-NAME -p DB-NAME --max_allowed_packet=16M < dump.sql
これでもエラーが出る場合はそもそも mysqldump のダンプの取り方を変えてみると良いでしょう
mysqldumpではデフォルトで全ての行を1度にINSERTするようなSQL文を吐き出します。
これをやめるオプションが --skip-extended-insert です。これを指定してdumpします。
mysqldump -u USER-NAME -p DB-NAME --skip-extended-insert > dump.sql
mysql -u USER-NAME -p DB-NAME < dump.sql
MySQL5.7以降ではデフォルトで InnoDBで日本語全文検索が使えるようになりました。
SELECT version();
ALTER TABLE mytable ADD FULLTEXT KEY (title, content) WITH PARSER ngram;
対象テーブル「item_table」対象カラム「item_name」
インデックス名「item_name_fulltext_idx」
でフルテキストインデックスを作成する
CREATE FULLTEXT INDEX `item_name_fulltext_idx` ON `item_table` (`item_name`) WITH PARSER ngram;
デフォルトは4文字以上の単語が対象ですがその対象を2文字に変更することができます。
/etc/my.cnf
[mysqld]
innodb_ft_min_token_size=2
一度削除してから再度作成すればOKです。
DROP INDEX item_name_fulltext_idx ON item_table ;
CREATE FULLTEXT INDEX `item_name_fulltext_idx` ON `item_table` (`item_name`) WITH PARSER ngram ;
テーブル「category」 全データの
カラム「path_name」
の先頭に「/」を追加する
UPDATE category SET `path_name` = CONCAT("/",`path_name`) WHERE category_id = 12;
1010100000
1011100001
のハミング距離を MySQLで取得してみます。
672
737
SELECT BIT_COUNT(672 ^ 737) as hd;
結果
2
文字数が多い順に 100件取得します
SELECT
* , CHAR_LENGTH(カラム名) as MOJI_LENGTH
FROM
my_table
ORDER BY
MOJI_LENGTH DESC
LIMIT 100
「外部キー制約」はいわゆる『親テーブル - 子テーブル』というテーブル関係において 子テーブルに設定するキー制約です。
MySQLでは以下の条件を満たす時に外部キー制約を設定することができます
・親テーブルと子テーブルが両方InnoDBであること
・子テーブルのキーを設定するカラムと親テーブルの参照するカラムの型が一致していること
・親テーブルの参照するカラムにインデックスが設定されていること
親テーブル: user_table
子テーブル: user_detail_table
紐付けるカラム: user_table.user_id <-> user_detail_table.user_id
ALTER TABLE
user_detail_table
ADD FOREIGN KEY
(user_id)
REFERENCES
user_table(user_id)
ON UPDATE
親テーブル更新時の動作
ON DELETE
親テーブル削除時の動作
;
設定文字列 | 動作 |
---|---|
RESTRICT | エラーを発生させる(デフォルト値) |
NO ACTION | エラーを発生させる(RESTRICTと同じ挙動) |
CASCADE | 親テーブルと同じ処理(値の更新、データの削除)を行う |
SET NULL | 子テーブルにNULLをセットする |
(注意) CASCADE を設定したとき、小テーブルにデータを持たない親テーブルのデータを削除しようとするとエラーとなります。
mysql のTIMESTAMP型カラムのデフォルト値の設定について
古くから mysql を使ってきた方は意外と気づいてないかもしれませんが
mysql 5.6から timestam 型のカラムにはデフォルト値を明示的に指定しないといけなくなっています
(今のところ問題なく動作はしていますが。)
指定しない場合は mysql のエラーログに以下のようなエラー文が記録されているはずです
TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
このエラーをなくすには mysql の create 文で以下のように明示的に指定してあげます
create table my_table(
id int(10) unsigned NOT NULL auto_increment,
user_name varchar(255) NOT NULL ,
modified_date timestamp default current_timestamp()
);
mysql のログを logrotate を使ってローテーションさせる
mysql のログ
/var/log/mysqld.log
/var/log/mysql_slow.log
などを logrotate を使ってローテーションさせます。
vi /etc/logrotate.d/mysql
/var/lib/mysql/mysqld.log {
# create 600 mysql mysql
notifempty
daily
rotate 5
missingok
postrotate
# just if mysqld is really running
if test -x /usr/bin/mysqladmin && \
/usr/bin/mysqladmin ping &>/dev/null
then
/usr/bin/mysqladmin flush-logs
fi
endscript
}
/var/lib/mysql/mysqld.log を 現在運用中の mysql のログディレクトリを指定します
/var/lib/mysql/mysqld.log {
↓
/var/log/mysql_slow.log /var/log/mysqld.log {
touch 600 /root/.my.cnf
chmod 600 /root/.my.cnf
vi /root/.my.cnf
[mysqladmin]
password = パスワード
user= root
vi /etc/my.cnf
[mysqladmin]
password = YOUR_PASS_WORD
user= root
mysql -uroot -p【ルートのパスワード】 -D mysql -e "SELECT version()"
表示例
+-----------+
| version() |
+-----------+
| 5.7.17 |
+-----------+
または MySQLにログイン中なら(接続DBはどれでもよい)
select version();
でも取得できます。
mysql -V
表示例
mysql Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using EditLine wrapper
クライアントバージョン 14.14
サーババージョン 5.7.17
です。
接続元 : localhost のみ
ユーザ名 : hoge
パスワード : Fugafuga1#
データベース名 : mydb
権限 : 全て
GRANT ALL PRIVILEGES ON mydb.* TO 'hoge'@'localhost' IDENTIFIED BY 'Fugafuga1#' WITH GRANT OPTION;
select * from user;
接続元 : どこからでも可能
ユーザ名 : hoge
パスワード : fugafuga
データベース名 : mydb
権限 : SELECT, INSERT, UPDATE, DELETE のみ
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* to hoge@"%" IDENTIFIED BY 'password' WITH GRANT OPTION;
MySQL5.7以降ではデフォルトで「validate_password_policy」が「MEDIUM」に設定されています。
(アルファベット大文字、アルファベット小文字、数字、記号がかならず1文字含まれてないといけない)
これを回避するには
SET GLOBAL validate_password_policy=LOW;
とします。
確認するには
show variables like 'validate_password%';
とします。
MySQLで累計を求めるには変数を使うと簡単です。
SET @a;
SELECT
data_id, price, @a:=@a+price as price_ruikei
FROM
my_table
ORDER BY
modified_date;
MySQL server has gone away というエラーが出ることがあります。 これは最後のMySQL接続から時間が経って、自動的にMySQLサーバがタイムアウトした時に発生します。 タイムアウト時間は PHPの場合 phpinfo(); で表示される画面の
mysql.connect_timeout
の項目で見ることができます。デフォルト 60秒。
このタイムアウト時間を長くするには PHPの場合
ini_set('mysql.connect_timeout', 180);
ini_set('default_socket_timeout', 180);
とします。(3分に設定する場合)
またPHPなどのプログラムでMySQLクエリーを発行する前に再接続をしておくと良いです PHPフレームワークCodeIgniterの場合
$this->db->reconnect();
で再接続を行います。
MySQLで カラム「modified_date」が「現在時刻より 5分前以前に更新された」データを取得するには
SELECT
*
FROM
テーブル名
WHERE
modified_date < CURRENT_TIMESTAMP + INTERVAL - 5 MINUTE ;
MINUTEのところは以下の文字が使用できます。
YEAR
MONTH
DAY
-----
WEEK
-----
HOUR
MINUTE
SECOND
-----
MICROSECOND(マイクロ秒)
create table my_dt(
test_name varchar(200) comment 'カラムのコメント'
)
engine=MyISAM
default charset=utf8
comment='テーブルのコメント';
テーブル(my_dt)のカラムコメントを表示する
show full columns from my_dt;
MySQLのダンプコマンド【mysqldump】は一行ずつのINSERTコマンドをでダンプしません。 (複数行を一度にINSERTする) この書式ではメモリを大量に使用しますし、SQLiteのSQL文に対応しませんので一行ずつのINSERTコマンドでダンプします。
また最初に構造だけ取り出しておくのも良いです。(DBエンジンや インデックスを見直す時に便利)
mysqldump --no-data -h【サーバ名】 -u【ユーザ名】 -p【パスワード】【データベース名】 > dump_table_desc.sql
mysqldump -c --order-by-primary --skip-extended-insert -h【サーバ名】 -u【ユーザ名】 -p【パスワード】【データベース名】 【テーブル名】 > dump.sql
>> -c オプションをつけるとINSERTするカラム名もファイルに書きだされます。 より小さいファイルサイズの方が良い場合はこのオプションを外すといいでしょう <<
あるリストの中に存在するデータを取得するときなどにIN演算子を使用します。
使い方は
リストの中に存在するデータを取得する WHERE col_name IN (value, ...)
リストの中に存在しないデータを取得する WHERE col_name NOT IN (value, ...)
具体的には
SELECT * FROM my_table WHERE data_id IN(1,3,5,7,9,11);
とします。
hogeテーブルをfugafugaというテーブルにコピーする方法。
CREATE TABLE fugafuga LIKE hoge; INSERT INTO fugafuga SELECT * FROM hoge;
最新x件を残して残りすべてを削除するSQLはMySQLのユーザー変数を使って下記のように記述します。
(例ではキーとなるカラムを持たない検索ログの場合。)
SET @d = ( SELECT search_date FROM my_table ORDER BY search_date DESC limit 100,1 ); DELETE FROM my_table WHERE search_date < @d;
よく 検索結果などに『◯◯件 ヒットしました』と表示するWEBアプリがあります。
その時に,
件数を取得するSQL文は
SELECT * FROM data_table; SELECT count(*) AS count FROM data_table;
とすることが多いと思いますが、SELECT時に下記のように「SQL_CALC_FOUND_ROWS」を追加しておいて、その後 FOUND_ROWS() を記述するとかなり高速に取得できます。
SELECT SQL_CALC_FOUND_ROWS * FROM data_table; SELECT FOUND_ROWS() AS count
がSQL文が複雑な場合は逆に遅くなることもあるようです。
http://ma-bank.com/item/998
check table my_table
repair table my_table
ORDER BY で NULL値を最後にしてソートする方法
オラクルの場合だと簡単に
■ ORACLE
ORDER BY my_field ASC NULL LAST
と記述すればOKですが、MySQLでは次のように記述します。
■ MySQL
ORDER BY IF(ISNULL(my_field),1,0),my_field;
または少し簡単に以下のように記述します
ORDER BY my_field IS NULL, my_field ASC;
MySQLでTEXT / BLOG型にインデックスをはろうとするとエラーとなります。
そこで、サイズを指定してインデックスをはります。
対象テーブル:data_dt インデックス名:text_name_idx カラム:text_name
の時下記のように記述します。
create index text_name_idx on data_dt(text_name(255));
MySQLで文字数(xx文字以上)によるSELECTをするには CHAR_LENGTH を使用する。
SELECT
*
FROM
table
WHERE
CHAR_LENGTH(`title_name`) > 20
ORDER BY
CHAR_LENGTH(`title_name`)
limit 1000
mysql -h ホスト名 -uユーザー名 -p DB名
mysql -h ホスト名 -uユーザー名 -p DB名 < テキストファイル名
とすると、パスワード入力が促され、入力後に実行されます。
あるテーブル「test_table」のカラム「price_no」を小数点二桁まで扱えるようにするには
ALTER TABLE
test_table
MODIFY
price_no decimal(10,2) default NULL ;
とします。 (10,2)というのは 全部で10桁、小数点2桁 という意味です。 例
12345678.12
MySQL で小数点を表す型は2つあります。
decimal , numeric
DECIMAL および NUMERIC 型は真数値データ値を格納します。これらの型は、金銭データを扱う場合など、正確な精度を保持することが重要な場合に使用されます。MySQL では、NUMERIC は DECIMAL として実装されるので、DECIMAL に関する次の注意事項が NUMERIC にも同様に適用されます。
float , double
FLOAT および DOUBLE 型は概数値データ値を表します。MySQL は、単精度値には 4 バイトを、倍精度値には 8 バイトを使用します。
浮動小数点値は概数値であり、真数値としては格納されないので、比較で値を真数値として扱おうとすると、問題が発生することがあります
MySQLのスローログ(実行に時間がかかったSQLクエリ)を取得するには
# 1秒以上かかったクエリを mysql_slow.log に保存する
slow_query_log=ON
long_query_time=1
slow_query_log_file=/var/log/mysql_slow.log
# インデックスを使わない検索を スローログに追加する
# log-queries-not-using-indexes
touch /var/log/mysql_slow.log
chown mysql /var/log/mysql_slow.log
chgrp mysql /var/log/mysql_slow.log
service mysqld stop
service mysqld start
# mysqladmin コマンドで確認する
mysqladmin -uroot -p status
# スローログを表示する
cat /var/log/mysql_slow.log
現在のMySQLの設定をみるには MySQLから
show variables;
MySQLの設定は( /etc/my.cnf )を書き換える。
設定例は
key_buffer = 384M sort_buffer_size = 2M read_buffer_size = 2M
key_buffer = 256M sort_buffer_size = 1M read_buffer_size = 1M
key_buffer = 16M sort_buffer_size = 512K read_buffer_size = 0
key_buffer = 16K sort_buffer_size = 64K read_buffer_size = 0
このあたりを参考に必ず設定する。
またMySQL ABでは,「key_buffer」の値はマシンに搭載しているメモリーの1/4を推奨値としている。
http://vine-linux.ddo.jp/linux/sql/mycnf.php
http://www.819410.com/FreeBSD6/shop/-145.html
MySQLのデータを<b>直接データファイル群から復元</b>するには以下のようにする。
MySQLのデータは
/var/lib/mysql/DB名/
にあるので(RedHat系Linuxの場合)直接(/DB名/)以下の全データを保存してバックアップする。
myisamchk *.MYI myisamchk *.MYI | grep worning
リストアしたいマシンの
/var/lib/mysql/
以下に直接データディレクトリをコピーする。/var/lib/mysql/DB名)
また権限は
所有者:mysql グループ:mysql ディレクトリ「DB名」の権限:700(drwx------) 「DB名」内のファイルの権限:660(-rw-rw----)
とすればよい。
テーブルに ユニーク制約を追加するには
ALTER TABLE table_name ADD CONSTRAINT UNIQUE(column_name);
と記述します。
SELECT時に日付カラム( 2007-01-23 12:30:59 )を年・月・日に分解して取得すると便利です。
SELECT DATE_FORMAT(CurDate(),'%Y') as year , DATE_FORMAT(CurDate(),'%m') as month , DATE_FORMAT(CurDate(),'%d') as day
DATE_FORMAT のオプション(指定子)は以下の通り 指定子 説明 %M 月の名前(January..December)。 %W 曜日名(Sunday..Saturday)。 %D 英語のサフィックス付きの日付(0th、1st、2nd、3rd など)。 %Y 4 桁の数値で表した年。 %y 2 桁の数値で表した年。 %X 日曜日を週の最初の日とした場合の週に使用する、4 桁の数値で表した年。%V と組み合わせて使用。 %x 月曜日を週の最初の日とした場合の週に使用する、4 桁の数値で表した年。%v と組み合わせて使用。 %a 略式の曜日名(Sun..Sat)。 %d 数値で表した日付(00..31)。 %e 数値で表した日付(0..31)。 %m 数値で表した月(00..12)。 %c 数値で表した月(0..12)。 %b 略式の月名(Jan..Dec)。 %j 年間を通した日にち(001..366)。 %H 時(00..23)。 %k 時(0..23)。 %h 時(01..12)。 %I 時(01..12)。 %l 時(1..12)。 %i 数値で表した分(00..59)。 %r 12 時間形式の時刻(hh:mm:ss に続けて AM または PM)。 %T 24 時間形式の時刻(hh:mm:ss)。 %S 秒(00..59)。 %s 秒(00..59)。 %f マイクロ秒(000000..999999)。 %p AM または PM %w 曜日(0=Sunday..6=Saturday)。 %U 日曜日を週の最初の日とした場合の週(00..53)。 %u 月曜日を週の最初の日とした場合の週(00..53)。 %V 日曜日を週の最初の日とした場合の週(01..53)。%X と組み合わせて使用。 %v 月曜日を週の最初の日とした場合の週(01..53)。%x と組み合わせて使用。 %% リテラルの ‘%’。 その他の文字はいずれも、解釈されずにそのまま結果にコピーされる。
参考:http://blog.tofu-kun.org/070620123532.php
MySQLでランダムにデータを「10件」取り出すには
SELECT * FROM table ORDER BY rand() limit 0 10;
とします。
ちなみにpostgreSQLでは
SELECT * FROM table ORDER BY random();
と書きます。
しかしこれはテーブル全件を走査するので非常に遅い。
そこで少し早くするには以下のようにします。
SELECT id , data FROM table ORDER BY rand() ;
で取り出したいカラムのみを指定する。
これだけでずいぶんと速くなります。
普通にカウントするには
SELECT count(*) FROM table1
としますが、このとき重複する行を取り除いてカウントするには
SELECT count( DISTINCT id ) FROM table1
とします。
ちなみに
SELECT count(*) FROM table1
より
SELECT count(id) FROM table1
の方が高速だと言われています。
MySQLにはクエリキャッシュの機能があり、これをONにするとクエリ結果をキャッシュから読み出すことが出来て高速な動作が期待できる。
show variables like 'query_cache_%'; +------------------------------+---------+ | Variable_name | Value | +------------------------------+---------+ | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 0 | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | +------------------------------+---------+ 5 rows in set (0.00 sec)
【query_cache_size】が【0】なのでクエリキャッシュが有効ではないことがわかる
「query_cache_type」をONに、「query_cache_size」を0より大きな適切な値に設定する必要がある。
/etc/my.cnf の [mysqld] の項目にクエリキャッシュに関する記述を追加する
[mysqld] # (query_cache_limit)これより大きい結果はキャッシュしない # (query_cache_min_res_unit) 4K が推奨値 # (query_cache_size)クエリキャッシュに割り当てるメモリ(Bytes) # (query_cache_type) 0:OFF 1:ON 2:DEMAND query_cache_limit=1M query_cache_min_res_unit=4k query_cache_size=24M query_cache_type=1
/etc/init.d/mysqld restart (または)service mysqld restart
<pre>SHOW STATUS LIKE 'Qcache%';</pre>
でクエリキャッシュの状態を確認する。
mysql> SHOW STATUS LIKE 'Qcache%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_free_blocks | 2 | 空きブロック数 | Qcache_free_memory | 24213616 | 空きメモリのサイズ (バイト) | Qcache_hits | 868 | クエリのヒット数 | Qcache_inserts | 900 | キャッシュに入れられたクエリの数 | Qcache_lowmem_prunes | 0 | メモリが足りないために削除された数 | Qcache_not_cached | 21 | キャッシュに入れられなかったクエリの数 | Qcache_queries_in_cache | 846 | キャッシュ内のクエリの数 | Qcache_total_blocks | 1711 | ブロックの領域の合計 +-------------------------+----------+ 8 rows in set (0.00 sec)
【Qcache_lowmem_prunes】を注意深く見ればいいことがわかります。
キャッシュは SELECT文にのみ適用される。
MySQL4.1以前を使用している場合 SQL文 の 'SELECT' の前に スペースが入っているとクエリキャッシュが有効にならないので注意。
(MySQL は先頭3文字のみを見て SEL であった場合のみクエリキャッシュに格納します。)
MySQLで「table1」というテーブルのデータを全件数削除するには
DELETE from table1
としますが、このとき auto_increment を指定してあるカラムがあると、そのauto_incrementの値はそのまま残ります。
(次にデータをINSERTした時に1番から始まらない)
なので auto_increment 値をリセットします
ALTER TABLE table1 PACK_KEYS =0 CHECKSUM =0 DELAY_KEY_WRITE =0 AUTO_INCREMENT =1
これでOK。
PACK_KEYS は MyISAM テーブルとだけ効果を発揮します。小さいインデックスを持ちたければ、このオプションを1に設定してください。これは通常更新スピードを遅くし、読み込みを早くします。オプションを0に設定すると、全てのキー パッキングが無効になります。これを DEFAULT に設定すると、ストレージ エンジンには長い CHAR や VARCHAR カラムだけをパックするように指令が出ます。 もし PACK_KEYS を利用しなければ、デフォルトでは文字列をパックしますが、数字はパックしません。もし PACK_KEYS=1 を利用すると、数字もパックされます
MySQL に全ての行のライブ チェックサムを維持させたければこれを1に設定してください。(これはテーブルが変更される度に MySQL が自動的に更新するチェックサムです。)これはテーブルの更新スピードを少し遅くしますが、壊れたテーブルを見つけるのが早くなります。CHECKSUM TABLE ステートメントはチェックサムをリポートします。(MyISAM のみです。)
DELAY_KEY_WRITE キー更新をテーブルが閉じられる時まで遅らせたければこれを1に設定してください。項4.2.3. 「システム変数」 内の delay_key_write システム変数についての説明を参照してください。(MyISAM のみです。)
日付(日付のみ。)を指定してデータをSELECTするには以下のように WHERE句において不等号で指定する。
SELECT
test_id,
test_name,
test_date
FROM
test_dt
WHERE
search_date < '2018-09-08';
SELECT
test_id,
test_name,
test_date
FROM
test_dt
WHERE
search_date BETWEEN '2018-09-01' AND '2006-09-05' ;
SELECT
test_id,
test_name,
test_date
FROM
test_dt
WHERE
search_date < DATE_SUB( CURDATE(),INTERVAL 5 DAY )
SELECT * , DATE_SUB( CURDATE(),INTERVAL 1 MINUTE ) as DATE_A
FROM test_dt
WHERE modified_date > DATE_SUB( NOW(),INTERVAL 1 HOUR )
5日後の場合は DATE_ADD()を使用する
CURDATE() の 代わりに NOW() を使用します。
正規表現を使って行を検索するには
WHERE REGEXP '正規表現'
とする。
例
SELECT id , artist_name FROM artist_dt WHERE artist_name REGEXP '^[a-z]+$';
また、エスケープシーケンス(\)を使う場合、シーケンスが1つの場合はMySQLに対するエスケープとみなされますので、正規表現としてのエスケープとする場合は2つ並べることになります。 バックスラッシュにマッチ SELECT '\\' REGEXP '\\\\'; ドット(正規表現ではなく文字としてのドット)にマッチ SELECT '.' REGEXP '\\.'; シングルクォートにマッチ SELECT '\'' REGEXP '\'';
■ 注意
MySQLでは日本語を含む正規表現は使用できません。
無理やり使う場合は下記のように記述します
× artist_name REGEXP '^[ア-オ]+' ◯ artist_name REGEXP '^(ア|イ|ウ|エ|オ)+'
日本語を含む正規表現を使用したい場合は下記の mregexp を使用します。
http://www.irori.org/tool/mregexp.html
1. /etc/my.cnf の
[mysqld] セクション内に
skip-networking
を追記する
2. mysqlをリスタート(再起動)する
/etc/init.d/mysqld restart
(エンコードUTF-8で運用の場合。)
[client]
default-character-set = utf8
[mysqld]
character-set-server = utf8
service mysqld restart
これでも解決しない時は次を試す
[mysqld]
skip-character-set-client-handshake
service mysqld restart
文字化けする
・各DB
・各テーブル
の character-set を確認すること
mysql> SET NAMES utf8;
で文字コードがutf8にセットされ文字化けがなおります。
chcp 65001
show variables like '%char%';
アカウント【root】 パスワード【pass】 DB名【mydb】 でパスワード入力もコマンドラインに書いてしまうには
mysql -uroot -ppass mydb [Enter]
でOK。
この例にならって mysqlのバックアップをコマンドライン1行で行うには、 アカウント【root】 パスワード【pass】 DB名【mydb】 バックアップファイル名【backup.dump】
mysqldump -uroot -ppass mydb > backup.dump [Enter]
でOK。
.bash_profile に保存して再ログイン、または直接実行
export HISTCONTROL=ignorespace
これでコマンドの先頭にスペースをつけるとhistoryに記録しない設定ができました。
この状態で先頭にスペースをつけてコマンドを実行します。
mysqldump -uroot -ppass mydb > backup.dump [Enter]
サーバステータスは、様々なサーバの状態を返します。
現在のサーバステータスを確認するには、以下のSQL文を発行します。
SHOW STATUS;
SHOW STATUS LIKE 'Qcache%';
http://www.limy.org/program/db/mysql/mysql_status.html
外部ホストから接続可能なユーザを作成する
use mysql;
SELECT Host, User, Password, Select_priv, Insert_priv,Update_priv, Delete_priv FROM user;
「Host」のところがlocalhost以外の場合外部から接続が可能です。( % の場合すべてのIPから接続が可能です)
例 ユーザ名【hoge】 パスワード【password】 データベース名【mydb】 の場合
GRANT ALL PRIVILEGES ON mydb.* to hoge@"%" IDENTIFIED BY 'password' WITH GRANT OPTION;
delete from mysql.user where Host="%" and User="hoge";
mysql -h HOST-NAME -u USER-NAME -p
show index from 【テーブル名】;
alter table 【テーブル名】 add index 【インデックス名】 (【フィールド名】);
例
テーブル「item_dt」
対象カラム「item_name」
に
インデックス名「item_name_idx」 のインデックスを作成します。
ALTER TABLE item_dt ADD INDEX item_name_idx(item_name);
TEXT型のように可変長テキストにインデックスを作成するには長さを指定します。 例(先頭255バイトまでのテキストにインデックスを貼る)
ALTER TABLE item_dt ADD INDEX item_name_idx(item_name(255));
DROP INDEX 【インデックス名】 ON 【テーブル名】;
EXPLAIN 【調査したいselect文】
表示されるデータの見方
【row】:テーブル読まれた行の数 (少ない方が良い。インデックス作成で激減する)
【type】:次の順番で早い順となる
・system, const(結果が単一行)
・eq_ref(UNIQUE or PRIMARY index使用)
・ref (index使用の単一パス検索)
・range ( indexの範囲検索)
・index(index全体をスキャン)
・ALL (全DBデータを検索)
status; または show variables like '%character%';
テーブル(my_table)の文字コードを確認するには
show create table my_table;
[mysqld] default-character-set=utf8 skip-character-set-client-handshake [mysql] default-character-set=utf8 [client] default-character-set=utf8
/etc/init.d/mysqld restart または service mysqld restart
内部コードがなんであれ、mysqlはクライアント毎に文字コードを設定できる
なので mysql へ接続後
SET NAMES utf8;
とすると文字コード UTF-8 になる。
なので、流しこむSQL文の先頭にこの1行を追加しておくだけでも良い。
参考:
http://www.mysql.gr.jp/frame/modules/bwiki/index.php?FAQ#dbf81e3d
SET NAMES と SET CHARACTER SETの違い↓
http://dev.mysql.com/doc/refman/4.1/ja/charset-connection.html
grant all privileges on dbname.* to username@hostname identified by 'passname';
username:ユーザ名
dbname:データベース名
hostname:接続元ホスト名
passname:パスワード
SELECT * from mysql.user; (全て表示)
SELECT Host,User,Password from mysql.user; (簡易表示)
MySQLではサブクエリーの代わりにテンポラリテーブルを使います。 もちろんMySQL5からサブクエリーも使えるようになりましたが、テンポラリテーブルの方が速度が早いようです。
CREATE TEMPORARY TABLE tmp1 ENGINE=MyISAM
SELECT * FROM test_dt
WHERE item_name like '%検索文字列%' ;
CREATE TEMPORARY TABLE tmp
SELECT 'buy'tablename,id,shop FROM buy;
INSERT INTO tmp
SELECT 'eat'tablename,id,shop FROM eat;
INSERT INTO tmp
SELECT 'inn'tablename,id,shop FROM inn;
INSERT INTO tmp
SELECT * from tmp;
DROP TABLE tmp;
GRANT all ON test_db.* TO sample@localhost IDENTIFIED BY 'password';
REVOKE ALL ON test_db.* FROM sample@localhost;
( 該当ユーザは一度 mysqlを終了して抜ける )
http://dev.mysql.com/doc/refman/4.1/ja/grant.html
GRANT FILE ON *.* TO sample@localhost IDENTIFIED BY 'password';
show grants for test_user@localhost;
flush privileges;
help
然るべき権限(user テーブルの Create_Prev)が必要です。
create database dbname
然るべき権限(user テーブルの Drop_Prev)が必要です。
drop database dbname
show databases
データベースを選択していない場合や、他のデータベースを指定する場合は、「show tables from dbname;」という書式になります。
show tables
show variables