web-dev-qa-db-ja.com

頻繁にクエリされる100,000レコードのMySQLテーブル

私はさまざまな種類の情報を格納するために、約100のテーブルの単一のデータベースを持っています。

最も重要なテーブルは、顧客の注文を格納するために使用される注文テーブルであり、現在および増加している現在では10万件を超えるレコードです。

このテーブルは、リアルタイム注文ダッシュボード、統計、分析などから必要な情報のさまざまな部分について、データベースで最もクエリされたテーブルです。

私は定期的にデータベースを監視しており、問題を追跡するためにデータベースで遅いクエリを有効にしています。

Mysqltunerのようなスクリプトを使用して、クエリを毎日吐き出しています。

また、mysqlslaを使用して、データベース内の最も遅い10個のクエリに関する情報を収集します。

sample stat
Count         : 11.48k  (30.66%)
Time          : 19.623758 s total, 1.709 ms avg, 239 µs to 2.475017 s max  (18.64%)
  95% of Time : 5.246833 s total, 481 µs avg, 239 µs to 1.095 ms max
Lock Time (s) : 14.460071 s total, 1.259 ms avg, 53 µs to 2.462555 s max  (41.38%)
  95% of Lock : 806.43 ms total, 74 µs avg, 53 µs to 137 µs max
Rows sent     : 1 avg, 0 to 9 max  (0.99%)
Rows examined : 6 avg, 1 to 28 max  (0.15%)

最も遅いクエリのほとんどは、上記の注文テーブルに関係しています。私はMyISAMをストレージエンジンとして使用しているため、次のような問題が発生する可能性があります。

  1. テーブルのロック
  2. インデックスの問題

どうすればこれらの統計を改善できますか?これらのテーブルに適切なインデックスを設定し、読み取りクエリを改善するためにそれらを微調整し続けました。

テーブルスキーマ

`orderid` int(11) NOT NULL AUTO_INCREMENT,
`cityid` tinyint(3) unsigned NOT NULL DEFAULT '1',
 `model_type` tinyint(1) unsigned DEFAULT '1',
`userid` int(11) DEFAULT NULL,
`usertype` char(1) DEFAULT NULL,
`time` time DEFAULT NULL,
`ordercode` char(8) DEFAULT NULL,
`restid` smallint(3) unsigned NOT NULL,
`areaid` smallint(3) unsigned DEFAULT NULL,
`restname` varchar(50) DEFAULT NULL,
`date` date NOT NULL,
`del_time` time NOT NULL,
`status` tinyint(3) unsigned NOT NULL,
`amount` float NOT NULL,
`deliverycharge` smallint(4) unsigned DEFAULT '0',
`tax` float NOT NULL,
`total` float NOT NULL,
`extras` varchar(255) DEFAULT NULL,
`requests` varchar(255) DEFAULT NULL,
`discount` float DEFAULT NULL,
`rdiscount` float DEFAULT NULL,
`reason` varchar(255) DEFAULT NULL,
`rest_order` tinyint(1) unsigned DEFAULT NULL,
`admin_user` varchar(25) DEFAULT NULL,
`mode` char(1) NOT NULL,
`priority_order` tinyint(1) unsigned DEFAULT '0',
`payment_mode` tinyint(1) unsigned DEFAULT '0',
`km` tinyint(3) unsigned DEFAULT NULL,
`order_type` tinyint(1) NOT NULL DEFAULT '1',
`coupon_discount` smallint(3) DEFAULT '0',
`pickup_time` time NOT NULL,
PRIMARY KEY (`orderid`),
KEY `cityid` (`cityid`),
KEY `date_3` (`date`,`status`,`mode`),
KEY `orderid` (`orderid`),
KEY `time` (`time`),
KEY `userid` (`userid`,`usertype`),
KEY `restid` (`restid`,`date`,`status`)

遅いログクエリ

SELECT `a`.`orderid`, `a`.`date`, `a`.`status`, `a`.`restname`, `a`.`admin_user`, `a`.`model_type`, `b`.`name` as cityname
FROM `tk_order_queue` AS a
INNER JOIN `tk_cities` AS b ON `a`.`cityid` = `b`.`id`
WHERE `a`.`date` =  '2012-06-30'
AND `a`.`status` =  0
AND `a`.`mode` =  1
ORDER BY `a`.`orderid` desc;
11
sheldon

すべてのクエリのWHERE句とGROUP BYおよびORDER BYステートメントを比較して、現在のインデックスがEXPLAINプランでそれらをサポートできることを確認する必要があります。

昨日、私はこの質問に答えました: InnoDBとMyISAMと多くのインデックス

その質問で、私はMyISAMテーブルにあなたもできることを提案しました

ALTER TABLE orders ROW_FORMAT=Fixed;

これはすべてのVARCHARをCHARとして扱います。すべての行は正確に同じ長さになります。これにより、ディスク容量が80%〜100%増加します。テーブルは、行レイアウトの最大サイズに行数を掛けたものに膨らみます。テーブルのサイズは2倍または3倍になります。

メリットはどこですか? MyISAMテーブルは、他に何も変更せずに、20%から30%高速で読み書きされます。

MySQLデータベースの設計とチューニング から72、73ページからそのことを学びました。

私は過去にこれについて書きました:

8
RolandoMySQLDBA