0

誰かが私を助けてくれたり、クエリを高速化する方法を説明してくれませんか? このクエリは、ほぼ 1GB のデータで (私のローカル マシンで) ほぼ 10 秒かかります。

これが私の説明と結果の説明です

    explain select p.delivery_date, p.delivery_hour, p.resource_id, p.participant_id, p.price, p.date_posted, hour(p.date_posted) as hour_date_posted, date(p.date_posted) as date_date_posted
    ,s.mw
from prices_report as p
left join schedules_report s
on s.delivery_date = p.delivery_date
                    AND s.type_id = p.type_id
            and s.delivery_hour = p.delivery_hour
                    and s.resource_id = p.resource_id
                    and s.participant_id = p.participant_id
                    and hour(s.date_posted) = hour(p.date_posted)
                    and date(s.date_posted) = date(p.date_posted)
WHERE p.delivery_date = '2012-05-22'
AND p.type_id = 'GEN'
ORDER BY p.delivery_date, p.resource_id, p.delivery_hour, p.participant_id, p.type_id, p.date_posted

ここに画像の説明を入力

結果の説明:
id: 1
選択タイプ: 単純な
テーブル: p
タイプ: ref
可能なキー: idx1
キー: idx1
key_len: 4
ref: const
行: 40258
追加: where を使用

id: 1
select type: simple
table: s
type: ref
可能なキー: idx1
key: idx1
key_len: 63
ref: const,APC_DB.p.delivery_hour,APC_DB.p.participant_id,APC_DB.p.resource_id,const
行: 99
追加:

テーブル構造:

  CREATE TABLE `prices_report` (
  `id` int(11) NOT NULL auto_increment,
  `delivery_date` date default NULL,
  `delivery_hour` int(2) default NULL,
  `participant_id` varchar(10) default NULL,
  `resource_id` varchar(15) default NULL,
  `type_id` varchar(10) default NULL,
  `price` float default NULL,
  `date_posted` datetime NOT NULL,
  `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `IDX1` USING BTREE (`delivery_date`,`resource_id`,`delivery_hour`,`participant_id`,`type_id`,`date_posted`)
) ENGINE=MyISAM AUTO_INCREMENT=5261441 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;


CREATE TABLE `schedules_report` (
  `id` int(11) NOT NULL auto_increment,
  `delivery_date` date default NULL,
  `delivery_hour` int(2) default NULL,
  `participant_id` varchar(15) default NULL,
  `resource_id` varchar(20) default NULL,
  `type_id` varchar(10) default NULL,
  `mw` float default NULL,
  `loss_factor` float default NULL,
  `date_posted` datetime NOT NULL,
  `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `IDX1` USING BTREE (`delivery_date`,`delivery_hour`,`participant_id`,`resource_id`,`type_id`,`date_posted`)
) ENGINE=MyISAM AUTO_INCREMENT=43369 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;

百万の感謝

4

1 に答える 1

2

問題は「ファジーマッチング」にあるようです:

LEFT JOIN ... ON ...
and hour(s.date_posted) = hour(p.date_posted)
and date(s.date_posted) = date(p.date_posted)

p の行に触れるたびに、MySQL に s のすべての行を計算させますhour(s.date_posted)date(s.date_posted)

これを試してください:

and s.date_posted
  BETWEEN DATE_SUB(p.date_posted, INTERVAL TIME_TO_SEC(MAKETIME(0,MINUTE(p.date_posted),SECOND(p.date_posted))) SECOND)
  AND DATE_ADD(DATE_SUB(p.date_posted, INTERVAL TIME_TO_SEC(MAKETIME(0,MINUTE(p.date_posted),SECOND(p.date_posted))) SECOND), INTERVAL 1 HOUR)

編集:

閏秒が間違って計算されることに耐えることができる場合、これはより人間が読みやすいものとして書くことができます

and s.date_posted
  BETWEEN DATE_SUB(p.date_posted, INTERVAL 60*MINUTE(p.date_posted)+SECOND(p.date_posted) SECOND)
  AND DATE_ADD(DATE_SUB(p.date_posted, INTERVAL 60*MINUTE(p.date_posted)+SECOND(p.date_posted) SECOND), INTERVAL 1 HOUR)

編集 2: 上限の計算値の一部の繰り返しはBETWEEN意図的です: MySQL は一度だけ計算します。

編集 3: あなたSHOW CREATE TABLEの を見て、date_posted に個別のインデックスがなく、結合されたインデックスしかないことを理解しました。あなたは試してみたいかもしれません

ALTER TABLE `schedules_report` ADD INDEX(date_posted)
于 2012-05-24T02:00:40.707 に答える