3

数百万行のテーブルがあり、テーブルにクエリを実行していますが、インデックスなどを追加してクエリを最適化できるかどうかを知りたいです。

テーブルスキーマ:

CREATE TABLE `aggregate_data` (
  `impressions` int(10) unsigned NOT NULL,
  `clicks` int(10) unsigned NOT NULL,
  `leads` int(10) unsigned NOT NULL,
  `date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `country` varchar(2) COLLATE utf8_bin NOT NULL,
  `campaign_id` int(10) unsigned NOT NULL,
  `payout` decimal(12,6) NOT NULL,
  `revenue` decimal(12,6) NOT NULL,
  `creative_id` int(10) unsigned NOT NULL DEFAULT '0',
  `advertiser_id` int(11) unsigned NOT NULL DEFAULT '0',
  `offer_id` int(11) unsigned NOT NULL DEFAULT '0',
  `affiliate_id` int(11) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`country`,`campaign_id`,`date`),
  KEY `date_added` (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

SQLクエリ:

SELECT 
    DATE_FORMAT(`date`, "%Y-%m-01 00:00:00") AS `date`, 
    offer_id,
    country,
    @sum_impressions := SUM(impressions), 
    @sum_clicks := SUM(clicks), 
    @sum_leads := SUM(leads), 
    @sum_payout := SUM(payout), 
    @sum_revenue := SUM(revenue)
FROM aggregate_data
WHERE `date` >= '2012-12-00 00:00:00'
GROUP BY country, offer_id, MONTH(`date`), YEAR(`date`)

説明を行うと、テーブル内のすべての行を使用していることが常に通知されます。

+----+-------------+----------------+------+---------------+------+---------+------+--------+----------------------------------------------+
| id | select_type | table          | type | possible_keys | key  | key_len | ref  | rows   | Extra                                        |
+----+-------------+----------------+------+---------------+------+---------+------+--------+----------------------------------------------+
|  1 | SIMPLE      | aggregate_data | ALL  | date_added    | NULL | NULL    | NULL | 809715 | Using where; Using temporary; Using filesort |
+----+-------------+----------------+------+---------------+------+---------+------+--------+----------------------------------------------+

WHERE句のために「Usingwhere」を使用し、group byのために「Usingtemporary」を使用し、group byのためにfilesortを使用します(私は思います)。

ここで、他にどのようなインデックスなどを追加する必要があるので、このクエリを最適化します。行が大きくなると、実行に数秒かかります。

このSELECTステートメントは「INSERTINTO...ON DUPLICATE KEY UPDATE」ステートメントの一部であるため、「@sum_impressions」などの変数が使用されます。

4

3 に答える 3

1

いくつかのアプローチが可能です。

  • RANGE パーティショニングを使用して、テーブルを年ごとに分割できます。

  • バッチを実行して毎月の合計を保存してから、totalsテーブルに対してクエリを実行できます。その名前から、すでにバッチ生成されているaggregate_dataように見えるので、それほど難しくなく、費用もかからないかもしれません。

  • でインデックスを作成してみることができますが、 でインデックスを作成すると、より良い結果が得られる (そして、より多くのディスク領域と時間date, country, offer_idを浪費する) 可能性があると思います(この方法では、クエリが必要とするすべてのデータが既にインデックスに含まれています。データ テーブルへのアクセスが必要です (もちろん、これには代償が伴います (パフォーマンス))。に分割することで、さらに優れた結果を得ることができます。INSERTdate, country, offer_id, impressions, clicks, leads, payout, revenueINSERTdateyearmonth

問題が発生した場合は、スーパー インデックスのパフォーマンスをテストします (ただし、アプリ全体を適切にシェイクダウンします。パーツによってパフォーマンスへの影響が異なる可能性があります)。次に、2 つのテーブルを持ち、同期を処理することを意味する場合でも、バッチ ソリューションを試してみます。

于 2013-01-14T19:28:02.983 に答える
1

テーブル構造を見るだけで:

  • 3 一部の主キーは、innodb がクラスター化されたインデックスを実行する方法のために、そのテーブルを非効率にしますが、「id autoincrement not null primary key」が役立つ可能性があります。
  • country次に、一意性を維持するために「unique ( , campaign_id, date)」制約を 追加します。
  • さらに、「key (country, offer_id)」によるグループのインデックス。場合によっては月/年もそのインデックスに追加します。
于 2013-01-14T19:31:16.007 に答える
1

うーん、これはどこのインデックスが事態を悪化させている可能性があるケースです。クエリがインデックスをスキャンしてから元のデータを読み取るため、インデックスは事態を悪化させる可能性がありますが、順序が正しくありません。データがメモリよりも大きい場合、不要なキャッシュ ミスが発生する可能性があります。

1 つの解決策は、データを日付で分割することです。

1 つのアイデアは、日付、国、および offer_id (1 つのインデックス、3 つの部分) にインデックスを配置することです。

これが機能するかどうかはわかりません。問題は解決しwhereますが、半分しか解決しませんgroup by

年と月が別々の列で、クエリが次のようになっているとします。

WHERE year >= 2012 and
GROUP BY country, offer_id, month, year

次に、(年、月、国、offer_id) のインデックスは、インデックスを使用するだけで満たすことができwhereますgroup by。異なる粒度の日付を混在させるとどうなるかわかりません。これは、日付ごとに (おそらく月レベルで) パーティショニングしてから、count、offer_id、および date でインデックスを作成することにつながります。(一部のデータベースは、インデックスで年 (日付) を使用できる関数インデックスを実際にサポートしています。)

于 2013-01-14T19:22:25.993 に答える