在大多数查询中,我的表现都非常差。我已经阅读了很多关于stackoverflow的内容,但是仍然有一些问题,也许有人可以帮忙或者给我任何提示吗?
基本上,我正在预订网站上,除其他表格外,还有以下表格:
对象
+----+---------+--------+---------+------------+-------------+----------+----------+-------------+------------+-------+-------------+------+-----------+----------+-----+-----+ | 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 | +----+------------+-----------+-----------+---------+--------+
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或INSERTs的表而设计的。因此,当前对象使用MyISAM并保留InnoDB。这是一个好主意吗?有更好的选择吗?
3-我需要查询在一定时期(在from_date和end_date之间)可用的那些对象。
但是,当我使用建议的解决方案时,查询会在返回任何结果之前超时(因此它确实很慢):
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
我究竟做错了什么?进行此类查询的最佳解决方案是什么?其他网站如何做?我的数据库结构不是最适合此的还是仅仅是查询?
我还有其他问题,但我将非常感谢您对此提供的任何帮助!非常感谢您的任何提示或建议!
似乎您正在寻找任何基于提供的开始/结束日期没有保留冲突的“对象”。进行coalcece()以始终包含保留中从未找到的那些对象是一个不错的选择,但是,作为左联接,我将尝试在找到日期的地方进行左联接,并忽略所有找到的对象。就像是
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(以及迄今为止),您正在专门寻找占用此时间段的预留空间。如果找到它们,则不允许这样做,因此WHERE子句将查找“ r.object_id IS NULL”(即:在您提供的日期范围内未发现任何冲突)
从我先前的答案扩展,并通过在(id,from date)和(id,to date)上有两个不同的索引,您可以通过分别加入每个索引的保留并期望两个保留集中的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