如何提高连接多个表的select性能

bpzcxfmw  于 2021-06-25  发布在  Mysql
关注(0)|答案(3)|浏览(338)

我有下面的mysql select语句,它在一个小数据集上正常工作,但在卷增加时停止工作:

SELECT DISTINCT Bookings.BookingId, Bookings.ResortId, Bookings.WeekBeginning, Bookings.DepartDate, Bookings.CancelledDate,Clients.FirstName, Clients.LastName, Clients.Email, Clients.Address1, Clients.City, Clients.State, Clients.CountryId, Clients.ClientType, Countries.Country, BookingAccommodation.AccomId, BookingAccommodation.ShareType, BookingProgram.ProgramId, Programs.ProgramDesc
    FROM Bookings, Clients, BookingProgram, BookingAccommodation, Countries, ClientType, Programs
    WHERE Bookings.BookingId = BookingProgram.BookingId
       AND Bookings.BookingId = BookingAccommodation.BookingId
       AND Bookings.WeekBeginning >= '2016-10-01' 
       AND BookingAccommodation.Nights > 0
       AND Clients.ClientId = Bookings.ClientId
       AND Clients.Email <> ''
       AND Clients.CountryId = Countries.CountryId
       AND Programs.ProgramId = BookingProgram.ProgramId

bookings中大约有10k条记录,bookingaccommodation和bookingprograms中的每一条记录都有25k条记录,虽然量不大,但查询只需950秒。我正在本地mamp服务器上的phpadmin的sql窗口中运行查询。
将其拆分为3个查询,每个查询的结果在几秒钟内返回:

SELECT DISTINCT Bookings.BookingId, Bookings.ResortId, Bookings.WeekBeginning, Bookings.DepartDate, Bookings.CancelledDate, Clients.FirstName, Clients.LastName, Clients.Email, Clients.Address1, Clients.City, Clients.State, Clients.CountryId, Clients.ClientType, Countries.Country
     FROM Bookings, Clients, Countries, ClientType
    WHERE Bookings.WeekBeginning >= '2016-10-01' 
       AND Clients.ClientId = Bookings.ClientId
       AND Clients.Email <> ''
       AND Clients.CountryId = Countries.CountryId

SELECT DISTINCT Bookings.BookingId, BookingAccommodation.AccomId, BookingAccommodation.ShareType
    FROM Bookings, BookingAccommodation
    WHERE Bookings.BookingId = BookingAccommodation.BookingId
       AND Bookings.WeekBeginning >= '2016-10-01' 
       AND BookingAccommodation.Nights > 0

SELECT DISTINCT Bookings.BookingId, BookingProgram.ProgramId, Programs.ProgramDesc
    FROM Bookings, BookingProgram, Programs
    WHERE Bookings.BookingId = BookingProgram.BookingId
       AND Bookings.WeekBeginning >= '2016-10-01' 
       AND Programs.ProgramId = BookingProgram.ProgramId

bookingaccommodation和bookingprogram中有多个记录,但我只需要每个记录中的一个记录,因此选择distinct。
预订的主键是bookingid。
bookingaccommodation的主键是bookingid、accomdate、accomid
bookingprogram的主键是bookingid、programid、accomtype
我试图用连接和子查询重写查询,但显然做得不对。如何将这3个查询连接回一个性能良好的查询中?

xoshrz7s

xoshrz7s1#

我没有花更多的时间来改进select语句,因为它访问了太多的表,我选择将它拆分为单独的查询,正如我在最初的问题中概述的那样。
最后,这是最快的实际解决办法。

omqzjyyz

omqzjyyz2#

试着把它改成

SELECT DISTINCT Bookings.BookingId, Bookings.ResortId, 
Bookings.WeekBeginning, Bookings.DepartDate, Bookings.CancelledDate,
Clients.FirstName, Clients.LastName, Clients.Email, Clients.Address1, 
Clients.City, Clients.State, Clients.CountryId, Clients.ClientType, Countries.Country,
BookingAccommodation.AccomId, BookingAccommodation.ShareType, BookingProgram.ProgramId,
Programs.ProgramDesc
    FROM Bookings
    JOIN Clients ON Clients.ClientId = Bookings.ClientId AND Bookings.WeekBeginning >= '2016-10-01' AND Clients.Email <> ''
    JOIN BookingProgram ON Bookings.BookingId = BookingProgram.BookingId
    JOIN BookingAccommodation ON Bookings.BookingId = BookingAccommodation.BookingId AND BookingAccommodation.Nights > 0
    JOIN Countries ON Clients.CountryId = Countries.CountryId
    JOIN Programs ON Programs.ProgramId = BookingProgram.ProgramId
    WHERE Bookings.WeekBeginning >= '2016-10-01';

如果这不能得到您想要的结果,请尝试解释并查看查询计划。
请注意:我没有看到任何地方正在使用表clienttype,所以我没有将其包含在联接中

utugiqy6

utugiqy63#

这些是使用子查询而不是连接(mysql假设为fwiw)的基础。为伪代码道歉,我认为尽快回答是很重要的,因为这是我刚才面对的这个问题的热门之一。
客户预订了一艘游轮。客户还应说明他们的饮食(如素食、纯素、不含大豆等)。因此,我们有三张table:
预订
预订id、预订日期、预订时间、客户id
客户
客户id,客户名称,客户电话,客户id
饮食
饮食id,饮食名称
我们现在要向礼宾部提供一个完整的预订视图。
使用“连接”: SELECT Bookings.Booking_Id, Bookings.Booking_Date, Bookings.Booking_Time, Clients.Client_Name, Diets.Diet_Name FROM Bookings INNER JOIN Clients ON Bookings.Client_Id = Clients.Client_Id INNER JOIN Diets ON Clients.Client_DietId = Diets.Diet_Id 使用“子查询”:
我认为它是如何在这些单独的连接中创建“临时表”的——当然“临时表”可能是准确的低级实现,也可能不是,等等。但有趣的是,子查询可能比大型连接(其他线程)更快。
我想从上面的示例中进行单独的连接:
首先,我需要加入客户的饮食,然后我加入“表”与预订。
因此,我的结论是(请注意,在引用子查询时表(重新)命名): SELECT [RELEVANT FIELDS HERE ETC] FROM (SELECT Clients.Client_Id, Clients.Client_Name, Diets.Diet_Name FROM Clients INNER JOIN Diets ON Clients.Client_DietId = Diets.Diet_Id) AS ClientDetailsWithDiets INNER JOIN Bookings ON Bookings.Booking_Id = ClientDetailsWithDiets.Client_Id 现在,如果要连接另一个表(例如分配给特定预订的工作人员),则上面的整个内容都将嵌套,以此类推: SELECT [RELEVANT FIELDS HERE ETC] FROM (SELECT [RELEVANT FIELDS HERE ETC] FROM (SELECT Clients.Client_Id, Clients.Client_Name, Diets.Diet_Name FROM Clients INNER JOIN Diets ON Clients.Client_DietId = Diets.Diet_Id) AS ClientDetailsWithDiets INNER JOIN Bookings ON Bookings.Booking_Id = ClientDetailsWithDiets.Client_Id) AS BookingDetailsFull INNER JOIN Staff ON BookingDetailsFull.Booking_Id = Staff.Booking_Id_Assigned

相关问题