所以我面临一个困难的场景,我有一个遗留应用程序,写得不好,设计不好,有一张桌子,t_booking
。这个应用程序有一个日历视图,其中,对于每个大厅,以及该月的每一天,使用此查询显示其预订状态:
SELECT mr1b.id, mr1b.idreserva, mr1b.idhotel, mr1b.idhall, mr1b.idtiporeserva, mr1b.date, mr1b.ampm, mr1b.observaciones, mr1b.observaciones_bookingarea, mr1b.tipo_de_navegacion, mr1b.portal, r.estado
FROM t_booking mr1b
LEFT JOIN a_reservations r ON mr1b.idreserva = r.id
WHERE mr1b.idhotel = '$sIdHotel' AND mr1b.idhall = '$hall' AND mr1b.date = '$iAnyo-$iMes-$iDia'
AND IF (r.comidacena IS NULL OR r.comidacena = '', mr1b.ampm = 'AM', r.comidacena = 'AM' AND mr1b.ampm = 'AM')
AND (r.estado <> 'Cancelled' OR r.estado IS NULL OR r.estado = '')
LIMIT 1;
(起初还有一个ORDER BY r.estado DESC
我拿出来了)
在适当的(我认为)索引之后,此查询每个需要0.004秒,并且整个日历视图在合理的时间内显示。有idhotel,idhall和date的索引。
现在,我有一个新模块,写得很好;-),它在另一个表中进行预订,但我必须在同一个日历视图中显示两种类型的预订。我的第一种方法是创建一个视图,连接两个表的内容,并从该视图而不是t_booking
中选择日历视图的数据。
视图的定义如下:
CREATE OR REPLACE VIEW
t_booking_hall_reservation
AS
SELECT id,
idreserva,
idhotel,
idhall,
idtiporeserva,
date,
ampm,
observaciones,
observaciones_bookingarea,
tipo_de_navegacion, portal
FROM t_booking
UNION ALL
SELECT HR.id,
HR.convention_id as idreserva,
H.id_hotel as idhotel,
HR.hall_id as idhall,
99 as idtiporeserva,
date,
session as ampm,
observations as observaciones,
'new module' as observaciones_bookingarea,
'events' as tipo_de_navegacion,
'new module' as portal
FROM new_hall_reservation HR
JOIN a_halls H on H.id = HR.hall_id
;
(表new_hall_reservation
具有相同的索引)
我尝试UNION ALL
代替UNION
,因为我认为这样效率更高。
嗯,之前的查询,t_booking
更改t_booking_hall_reservation
, 1.5秒,每个大厅和每天相乘,使日历视图无法完成。
该应用是spaguetti代码,因此,循环两次,一次超过t_booking
,然后超过new_hall_reservation
,并且结果合并有些困难。
是否可以调整视图以使此查询足够快?另一种方法?
由于
PS:我修改原始查询的次数越少,我就越不需要修改旧应用程序,这样修改的风险更小
答案 0 :(得分:0)
评论太长了。
视图(几乎)永远不会帮助提高性能。是的,他们使查询更简单。是的,它们包含重要的逻辑。但不,他们没有帮助表现。
一个关键问题是视图的执行 - 它通常不考虑整个表中的过滤器(尽管最新版本的MySQL在这方面更好)。
一个建议 - 可能是相当多的工作 - 是将视图表示为一个表格。当基础表发生变化时,您需要使用触发器更改t_booking_hall_reservation
。然后,您可以在表格上创建索引以实现性能目标。“
答案 1 :(得分:0)
t_booking,除非它是VIEW
,需要
INDEX(idhotel, idhall, date)
VIEWs
是句法糖;它们不会提高性能;有时它们比等效的SELECT
慢。