29

〜9mのレコードを持つ、大きくて狭いInnoDBテーブルがあります。実行count(*)またはcount(id)テーブル上での動作が非常に遅い (6 秒以上):

DROP TABLE IF EXISTS `perf2`;

CREATE TABLE `perf2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `channel_id` int(11) DEFAULT NULL,
  `timestamp` bigint(20) NOT NULL,
  `value` double NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ts_uniq` (`channel_id`,`timestamp`),
  KEY `IDX_CHANNEL_ID` (`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

RESET QUERY CACHE;
SELECT COUNT(*) FROM perf2;

ステートメントが頻繁に実行されるわけではありませんが、最適化することをお勧めします。http://www.cloudspace.com/blog/2009/08/06/fast-mysql-innodb-count-really-fast/によると、これは InnoDB にインデックスの使用を強制することで可能になるはずです。

SELECT COUNT(id) FROM perf2 USE INDEX (PRIMARY);

説明計画は問題ないようです:

id  select_type table   type    possible_keys   key     key_len ref     rows    Extra
1   SIMPLE      perf2   index   NULL            PRIMARY 4       NULL    8906459 Using index

残念ながら、ステートメントは以前と同じくらい遅いです。「SELECT COUNT(*)」によると、where句を使用しても、テーブルの最適化を試みても成功しませんでした。

COUNT(*)InnoDB でパフォーマンスを最適化する方法は何ですか?

4

3 に答える 3

22

MySQL 5.1.6 以降では、イベント スケジューラを使用して、カウントを統計テーブルに定期的に挿入できます。

まず、カウントを保持するテーブルを作成します。

CREATE TABLE stats (
`key` varchar(50) NOT NULL PRIMARY KEY,
`value` varchar(100) NOT NULL);

次に、テーブルを更新するイベントを作成します。

CREATE EVENT update_stats
ON SCHEDULE
  EVERY 5 MINUTE
DO
  INSERT INTO stats (`key`, `value`)
  VALUES ('data_count', (select count(id) from data))
  ON DUPLICATE KEY UPDATE value=VALUES(value);

完璧ではありませんが、カウントの必要な新鮮さだけ頻繁に実行するように簡単に調整できる自己完結型のソリューション (cron ジョブやキューなし) を提供します。

于 2013-12-19T03:57:50.037 に答える
18

当分の間、この近似を使用して問題を解決しました。

EXPLAIN SELECT COUNT(id) FROM data USE INDEX (PRIMARY)

rows上記のように、InnoDB を使用すると、Explain Planの列からおおよその行数を読み取ることができます。MyISAM を使用する場合、テーブル参照が最適化されているため、これは EMPTY のままになります。空の場合は、SELECT COUNT代わりに従来型にフォールバックします。

于 2013-10-09T18:44:36.710 に答える
17

INSERT@Che コードに基づいUPDATEて、トリガーを何度も使用しperf2て、統計テーブルの値をリアルタイムで最新の状態に保つこともできます。

CREATE TABLE stats (
 `key`   varchar(50)  NOT NULL PRIMARY KEY,
 `value` varchar(100) NOT NULL
);

それで:

CREATE TRIGGER `count_up` AFTER INSERT   ON `perf2` FOR EACH ROW UPDATE `stats`
SET   `stats`.`value` = `stats`.`value` + 1 
WHERE `stats`.`key` = 'perf2_count';

CREATE TRIGGER `count_down` AFTER DELETE ON `perf2` FOR EACH ROW UPDATE `stats`
SET   `stats`.`value` = `stats`.`value` - 1 
WHERE `stats`.`key` = 'perf2_count';

したがって、perf2テーブル内の行数は、このクエリを使用してリアルタイムで読み取ることができます。

SELECT `value` FROM `stats` WHERE `key` = 'perf2_count';

これには、 を実行する際のパフォーマンスの問題を解消できるという利点があり、 でCOUNT(*)データが変更された場合にのみ実行されperf2ます。

于 2013-12-19T04:38:20.603 に答える