4

ほとんどのクエリでパフォーマンスが非常に悪いです。私はstackoverflowについてたくさん読んだことがありますが、まだいくつか質問があります。誰かが私を助けたり、ヒントをくれたりする可能性がありますか?

基本的に、私は予約Webサイトで作業しており、特に次の表があります。

オブジェクト

+----+---------+--------+---------+------------+-------------+----------+----------+-------------+------------+-------+-------------+------+-----------+----------+-----+-----+
| id | user_id | status | type_id | privacy_id | location_id | address1 | address2 | object_name | short_name | price | currency_id | size | no_people | min_stay | lat | lng |
+----+---------+--------+---------+------------+-------------+----------+----------+-------------+------------+-------+-------------+------+-----------+----------+-----+-----+

またはMySQLの場合:

CREATE TABLE IF NOT EXISTS `objects` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'object_id',
  `user_id` int(11) unsigned DEFAULT NULL,
  `status` tinyint(2) unsigned NOT NULL,
  `type_id` tinyint(3) unsigned DEFAULT NULL COMMENT 'type of object, from object_type id',
  `privacy_id` tinyint(11) unsigned NOT NULL COMMENT 'id from privacy',
  `location_id` int(11) unsigned DEFAULT NULL,
  `address1` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `address2` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `object_name` varchar(35) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'given name by user',
  `short_name` varchar(12) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'short name, selected by user',
  `price` int(6) unsigned DEFAULT NULL,
  `currency_id` tinyint(3) unsigned DEFAULT NULL,
  `size` int(4) unsigned DEFAULT NULL COMMENT 'size rounded and in m2',
  `no_people` tinyint(3) unsigned DEFAULT NULL COMMENT 'number of people',
  `min_stay` tinyint(2) unsigned DEFAULT NULL COMMENT '0=no min stay;else # nights',
  `lat` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
  `lng` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1451046 ;


予約

+----+------------+-----------+-----------+---------+--------+
| id | by_user_id | object_id | from_date | to_date | status |
+----+------------+-----------+-----------+---------+--------+

またはMySQLの場合:

CREATE TABLE IF NOT EXISTS `reservations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `by_user_id` int(11) NOT NULL COMMENT 'user_id of guest',
  `object_id` int(11) NOT NULL COMMENT 'id of object',
  `from_date` date NOT NULL COMMENT 'start date of reservation',
  `to_date` date NOT NULL COMMENT 'end date of reservation',
  `status` int(1) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=890729 ;


いくつかの質問があります:

1-追加のキーを設定していません(プライマリを除く)-どこに設定し、どのキーを設定する必要がありますか?

2-私はMyISAMとInnoDBについて読みましたが、私の結論は、読み取り専用に関してはMyISAMの方が高速であるのに対し、InnoDBはより頻繁にUPDATEDまたはINSERTを取得するテーブル用に設計されているということです。そのため、現在、オブジェクトはMyISAMと予約InnoDBを使用しています。これを混ぜるのは良い考えですか?より良い選択肢はありますか?

3-特定の期間(from_dateとend_dateの間)に使用可能なオブジェクトを照会する必要があります。私は(とりわけ)stackoverflowに関するこの投稿を読みました:MySQLは日付が日付の間にない行を選択します

ただし、提案されたソリューションを使用すると、結果が返される前にクエリがタイムアウトします(したがって、非常に遅くなります)。

SELECT DISTINCT o.id FROM objects o LEFT JOIN reservations r ON(r.object_id=o.id) WHERE

COALESCE('2012-04-05' NOT BETWEEN r.from_date AND r.to_date, TRUE)
AND COALESCE('2012-04-08' NOT BETWEEN r.from_date AND r.to_date, TRUE)
AND o.location_id=201

LIMIT 20

私は何が間違っているのですか?そのようなクエリを実行するための最良の解決策は何ですか?他のサイトはどのようにそれを行いますか?私のデータベース構造はこれに最適ではありませんか、それともクエリだけですか?

もう少し質問がありますが、これについて助けを得ることができて本当にありがたいです!ヒントや提案をよろしくお願いします!

4

3 に答える 3

6

提供された開始日と終了日に基づいて、予約の競合がない「オブジェクト」を探しているようです。予約で決して見つからないものを常に含めるために coalesce() を実行することは問題ありませんが、左結合であるため、IS が見つかった場所で左結合を試み、見つかったオブジェクトを無視します。何かのようなもの

SELECT DISTINCT 
      o.id 
   FROM 
      objects o 
         LEFT JOIN reservations r 
            ON o.id = r.object_id
           AND (  r.from_date between '2012-04-05' and '2012-04-08'
               OR r.to_date between '2012-04-05' and '2012-04-08' )
   WHERE
          o.location_id = 201
      AND r.object_id IS NULL
  LIMIT 20

(object_id, from_date) と別の (object_id, to_date) による予約テーブルのインデックスを確保します。from_date between 範囲 (および to date も) を明示的に使用することで、この期間を占める予約を具体的に探しています。それらが見つかった場合、許可しないため、「r.object_id IS NULL」を検索する WHERE 句 (つまり、指定した日付範囲内で競合するものは何も見つかりません)

以前の回答から拡張し、(id、日付から) と (id、日付まで) に 2 つの異なるインデックスを作成することで、各インデックスの予約にそれぞれ参加し、両方の予約セットで NULL を期待することで、パフォーマンスが向上する可能性があります...

SELECT DISTINCT 
      o.id 
   FROM 
      objects o 
         LEFT JOIN reservations r 
            ON o.id = r.object_id
           AND r.from_date between '2012-04-05' and '2012-04-08'
         LEFT JOIN reservations r2 
            ON o.id = r2.object_id
           AND r2.to_date between '2012-04-05' and '2012-04-08'
   WHERE
          o.location_id = 201
      AND r.object_id IS NULL
      AND r2.object_id IS NULL
  LIMIT 20
于 2012-04-26T15:37:07.393 に答える
2

InnoDB と MyISAM テーブルを混在させることはしませんが、すべてのテーブルを InnoDB として定義します (Foring キーのサポートのため)。通常、_id サフィックスを持つすべての列は、適切なテーブルを参照する外部キーにする必要があります (object_id => オブジェクトなど)。

外部キーは自動的に定義されるため (MySQL 4.1.2 以降)、外部キーにインデックスを定義する必要はありませんが、reservations.from_date および reserved.to_date カラムに追加のインデックスを定義して、比較を高速化できます。

于 2012-04-26T11:36:51.587 に答える
1

これが 1 年前のものであることはわかっていますが、上記のソリューションを試した場合、ロジックは完全ではありません。クエリの開始前に開始し、クエリの終了後に終了する予約は見逃されます。またbetween、開始・終了が同時の予約には対応しておりません。

これは私にとってはうまくいきました:

SELECT venues.id
FROM venues LEFT JOIN reservations r
       ON venues.id = r.venue_id && (r.date_end >':start' and  r.date_start <':end')
WHERE r.venue_id IS NULL
ORDER BY venues.id
于 2013-07-27T03:26:26.617 に答える