我有以下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
预订中的约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中有多条记录,但我只需要一条记录,因此SELECT DISTINCT。
我试图用连接和子查询重写查询,但我显然没有做得对。如何将这3个查询加入到一个表现良好的查询中?
答案 0 :(得分:1)
这些是使用子查询代替联接的基础(MySQL假定为FWIW)。对伪代码表示歉意,我认为尽快回答非常重要,因为这是我刚才遇到的这个问题上的热门文章之一。
客户预订了游轮。服务对象还应指定饮食(例如素食,纯素食,无大豆等)。因此,我们有三个表:
预订
Booking_Id,Booking_Date,Booking_Time,Client_Id
客户
Client_Id,Client_Name,Client_Phone,Client_DietId
饮食
Diet_Id,Diet_Name
我们现在要向礼宾提供完整的预订视图。
使用“ JOINS”:
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
使用“ SUBQUERIES”:
我怎么想的是在那些单独的JOIN中创建“临时表”-当然,“临时表”可能是也可能不是准确的低级实现,等等。但是,有趣的是,子查询可能比大型联接要快(其他线程)。
我想从上述示例中进行单独的联接:
首先,我需要将客户的饮食与他们一起加入,然后将我的“餐桌”与预订一起加入。
因此,我最终得到了这一点(请注意在引用子查询时对表进行(重新)命名):
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
现在,如果要联接另一个表,例如分配给特定预订的Staff,则上面的整个内容将被嵌套,依此类推,例如:
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
答案 1 :(得分:0)
尝试将其更改为
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';
如果这不能获得您想要的结果,请尝试EXPLAIN并查看查询计划。
请注意:我没有看到表ClientType在任何地方被使用,所以我没有将它包含在JOIN中
答案 2 :(得分:-1)
而不是花费更多时间来尝试改进select语句,因为它碰到了这么多表我选择将其拆分为原始问题中概述的单独查询。
最后,这是最快的实际解决方案。