3

次のようなテーブルを含む percona mysql 5.6.13 データベースがあります。

CREATE TABLE `table1` (
  `table1_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`table1_id`),
  KEY `created_at` (`created_at`)
) ENGINE=InnoDB;

CREATE TABLE `table2` (
  `table1_id` int(10) unsigned NOT NULL,
  `cost` decimal(6,2) NOT NULL DEFAULT '0.00',
  KEY `table1_id` (`table1_id`)
) ENGINE=InnoDB;


CREATE TABLE `table3` (
  `table1_id` int(10) unsigned NOT NULL,
  `partner` enum('partner1', 'partner2', 'partner3', 'partner4') NOT NULL DEFAULT 'partner1',
  KEY `table1_id` (`table1_id`)
) ENGINE=InnoDB;

各テーブルには、約 150 万行あります。

次のクエリを実行すると、毎回 18 秒かかります。

SELECT t3.partner, SUM(t2.cost) AS cost FROM table1 t1 JOIN table2 t2 ON t1.table1_id = t2.table1_id JOIN table3 t3 ON t1.table1_id = t3.table1_id WHERE t1.created_at >= '2005-07-01' AND t1.created_at < '2008-09-20' GROUP BY 1;

cost / partner フィールドを table1 に非正規化すると、次のようになります。

ALTER TABLE table1 ADD `cost` decimal(6,2) NOT NULL DEFAULT '0.00', ADD `partner` enum('partner1', 'partner2', 'partner3', 'partner4') NOT NULL DEFAULT 'partner1', ADD KEY `partner` (`partner`);
UPDATE table1 t1 JOIN table2 t2 ON t1.table1_id = t2.table1_id SET t1.cost = t2.cost;
UPDATE table1 t1 JOIN table3 t3 ON t1.table1_id = t3.table1_id SET t1.partner = t3.partner;

次に、次のクエリを実行します。

SELECT t1.partner, SUM(t1.cost) AS cost FROM table1 t1 WHERE t1.created_at >= '2005-07-01' AND t1.created_at < '2008-09-20' GROUP BY 1;

最初は6秒かかり、その後は毎回2秒かかります(おそらくmysqlキャッシングのため)。

私が見つけたいと思っているのは、おそらくデータを非正規化せずに元のクエリを最適化/キャッシュする何らかの方法だと思います。
テーブルをマージすることはできません(例には含まれていない他のフィールドのためですが、テストの目的で/ここで正確にするために削除しました)。テーブル間でデータを複製することはできますが、私はそれがあまり好きではありません。それよりも優れた解決策があるはずです。
試すデータベース設定はありますか?
おそらく、より完全に非正規化されたデータを使用する NoSQL です。この種のシナリオでは、集約はかなり高速に機能しますか?
ありがとう :)

psクエリプランについて1つのコメントが求められました-where句によって選択された行の数はそれらすべてです。where を省略しても同じ結果になります。クエリ プランは次のとおりです。

+----+-------------+-------+-------+--------------------+------------+---------+------------------------+--------+-----------------------------------------------------------+
| id | select_type | table | type  | possible_keys      | key        | key_len | ref                    | rows   | Extra                                                     |
+----+-------------+-------+-------+--------------------+------------+---------+------------------------+--------+-----------------------------------------------------------+
|  1 | SIMPLE      | t1    | range | PRIMARY,created_at | created_at | 5       | NULL                   | 766380 | Using where; Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | t3    | ref   | table1_id,partner  | table1_id  | 4       | lsfs_main.t1.table1_id |      1 | NULL                                                      |
|  1 | SIMPLE      | t2    | ref   | table1_id          | table1_id  | 4       | lsfs_main.t1.table1_id |      1 | NULL                                                      |
+----+-------------+-------+-------+--------------------+------------+---------+------------------------+--------+-----------------------------------------------------------+
4

1 に答える 1

1

table2と の主キーがありませんtable3。少なくともtable32 つの列すべてを含む複数列の主キーをお勧めします。InnoDB-Tables はインデックス構成のテーブルであるため、これにより のルックアップが大幅に削減されますtable3。このような主キーを使用すると、MySQL は、さらにルックアップすることなく、すべての関連データをインデックスから直接取得できます。フィールドtable1_idは、複数列の主キーの最初の位置にある必要があります。

ユニークではないためtable2、簡単ではありません。(table1_id, cost)

于 2013-10-31T08:54:21.110 に答える