MySQL w/ Quota
MySQLサーバでデータベースにQuotaをかける方法を探していました。
結局、MySQLサーバ自体にはQuota機能がない。
それで、スクリプト等を利用して色々と試行錯誤されている情報を元に
自分なりにまとめてみました。
mysql_quota.php(Sebastian Marschingが書いた有名なスクリプト)
これはQuotaテーブルを作成して、ここに制限したいデータベース名と 制限値(単位はバイト)を設定して、定期的にスクリプトを実行することで データベースに対してInsertとCreateの権限を操作するって代物。 ただ、古いスクリプトなので色々と動かない箇所があったりした。
実行した後にFLUSH Privileges;を実行しないと有効にならなかったりする。
あと、MySQLのテーブル仕様だけどもデータを削除してもオーバーヘッドとして ゴミが残って実際の使用量が減らない場合がある。 phpMyAdminを利用している場合は、該当テーブルを選択して「テーブルを最適化する」を 実行すればよい。ただし、Insert権限がはく奪されている状態ではエラーになってできない。 管理者権限で実行するか、mysqlクライアントからoptimizeコマンドを発行するばよい。
mysql> optimize table <db名>.<テーブル名>; +-------------------------+----------+----------+----------+ | Table | Op | Msg_type | Msg_text | +-------------------------+----------+----------+----------+ | <DB名>.<テーブル名> | optimize | status | OK | +-------------------------+----------+----------+----------+ 1 row in set (0.00 sec)
ユーザ作成はこれ
CREATE USER 'ユーザ名'@'localhost' IDENTIFIED BY '***'; GRANT USAGE ON * . * TO 'ユーザ名'@'localhost' IDENTIFIED BY '***' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ; CREATE DATABASE IF NOT EXISTS `DB名` ; GRANT ALL PRIVILEGES ON `DB名` . * TO 'ユーザ名'@'localhost';
スクリプトはこれ。
#!/usr/bin/php -q <?PHP /* * MySQL quota script * written by Sebastian Marsching * */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Create table for quota data with the following statement: * * CREATE TABLE `Quota` (`db` CHAR(64) NOT NULL, * `limit` BIGINT NOT NULL, * `exceeded` ENUM('Y','N') DEFAULT 'N' NOT NULL, * PRIMARY KEY (`db`), UNIQUE (`db`)); * * The field 'db' stores the information for which database * you want to limit the size. * The field 'limit' is the size limit in bytes. * The field 'exceeded' is only used internally and must be * initialized with 'N'. */ /* * Settings */ $mysql_host = 'localhost'; $mysql_user = 'root'; // Do NOT change, root-access is required $mysql_pass = ''; $mysql_db = 'quotadb'; // Not the DB to check, but the db with the quota table $mysql_table = 'Quota'; /* * Do NOT change anything below */ $debug = 1; // Connect to MySQL Server if (!mysql_connect($mysql_host, $mysql_user, $mysql_pass)) { echo "Connection to MySQL-server failed!"; exit; } // Select database if (!mysql_select_db($mysql_db)) { echo "Selection of database $mysql_db failed!"; exit; } // Check quota for each entry in quota table $sql = "SELECT * FROM $mysql_table;"; $result = mysql_query($sql); while ($row = mysql_fetch_array($result)) { $quota_db = $row['db']; $quota_limit = $row['limit']; $quota_exceeded = ($row['exceeded']=='Y') ? 1 : 0; if ($debug) echo "Checking quota for '$quota_db'...\n"; $qsql = "SHOW TABLE STATUS FROM $quota_db;"; $qresult = mysql_query($qsql); if ($debug) echo "SQL-query is \"$qsql\"\n"; $quota_size = 0; while ($qrow = mysql_fetch_array($qresult)) { if ($debug) { echo "Result of query:\n"; var_dump($qrow); } $quota_size += $qrow['Data_length'] + $qrow['Index_length']; } if ($debug) echo "Size is $quota_size bytes, limit is $quota_limit bytes\n"; if ($debug && $quota_exceeded) echo "Quota is marked as exceeded.\n"; if ($debug && !$quota_exceeded) echo "Quota is not marked as exceeded.\n"; if (($quota_size > $quota_limit) && !$quota_exceeded) { if ($debug) echo "Locking database...\n"; // Save in quota table $usql = "UPDATE $mysql_table SET exceeded='Y' WHERE db='$quota_db';"; mysql_query($usql); if ($debug) echo "Querying: $usql\n"; // Dismiss CREATE and INSERT privilege for database mysql_select_db('mysql'); $usql = "UPDATE db SET Insert_priv='N', Create_priv='N' WHERE Db='$quota_db';"; mysql_query($usql); if ($debug) echo "Querying: $usql\n"; $usql = "flush privileges;"; mysql_query($usql); mysql_select_db($mysql_db); } if (($quota_size <= $quota_limit) && $quota_exceeded) { if ($debug) echo "Unlocking database...\n"; // Save in quota table $usql = "UPDATE $mysql_table SET exceeded='N' WHERE db='$quota_db';"; mysql_query($usql); if ($debug) echo "Querying: $usql\n"; // Grant CREATE and INSERT privilege for database mysql_select_db('mysql'); $usql = "UPDATE db SET Insert_priv='Y', Create_priv='Y' WHERE Db='$quota_db';"; mysql_query($usql); if ($debug) echo "Querying: $usql\n"; $usql = "flush privileges;"; mysql_query($usql); mysql_select_db($mysql_db); } } ?>