Inilah solusi yang tampaknya berhasil:
SELECT t.*, DATEDIFF(t.LatestAvailable, t.EarliestAvailable) AS LengthAvailable
FROM
(SELECT u.*,
COALESCE(b1.End, @StartOfWindow) AS EarliestAvailable,
COALESCE(b2.Start, @EndOfWindow) AS LatestAvailable
FROM LettingUnits u
LEFT OUTER JOIN LettingUnitBookings b1
ON (u.ID = b1.F_LU_ID AND b1.End BETWEEN @StartOfWindow AND @EndOfWindow)
LEFT OUTER JOIN LettingUnitBookings b2
ON (u.ID = b2.F_LU_ID AND b2.Start BETWEEN @StartOfWindow AND @EndOfWindow
AND b2.Start >= b1.End) -- edit: new term
) AS t
LEFT OUTER JOIN LettingUnitBookings x
ON (t.ID = x.F_LU_ID AND x.Start < t.LatestAvailable AND x.End > t.EarliestAvailable)
WHERE x.ID IS NULL AND DATEDIFF(t.LatestAvailable, t.EarliestAvailable) >= @WindowSize;
Outputnya adalah:
+-----+-------------+-------------------+-----------------+-----------------+
| ID | Name | EarliestAvailable | LatestAvailable | LengthAvailable |
+-----+-------------+-------------------+-----------------+-----------------+
| 123 | Foo Cottage | 2009-01-05 | 2009-01-10 | 5 |
| 123 | Foo Cottage | 2009-01-20 | 2009-01-25 | 5 |
| 456 | Bar Cottage | 2009-01-20 | 2009-01-31 | 11 |
+-----+-------------+-------------------+-----------------+-----------------+
Menganalisis ini dengan EXPLAIN
menunjukkan bahwa ia menggunakan indeks dengan cukup baik:
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 9 | Using where |
| 1 | PRIMARY | x | ref | F_LU_ID | F_LU_ID | 8 | t.ID | 2 | Using where; Not exists |
| 2 | DERIVED | u | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | b1 | ref | F_LU_ID | F_LU_ID | 8 | const | 0 | |
| 2 | DERIVED | b2 | ref | F_LU_ID | F_LU_ID | 8 | const | 0 | |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
Bandingkan dengan EXPLAIN
laporan untuk solusi diberikan oleh @martin clayton:
+----+--------------+---------------------+--------+---------------+---------+---------+------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+---------------------+--------+---------------+---------+---------+------+------+---------------------------------+
| 1 | PRIMARY | lu | system | PRIMARY,ID | NULL | NULL | NULL | 1 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
| 2 | DERIVED | <derived3> | ALL | NULL | NULL | NULL | NULL | 4 | Using temporary; Using filesort |
| 2 | DERIVED | <derived5> | ALL | NULL | NULL | NULL | NULL | 4 | Using where; Using join buffer |
| 5 | DERIVED | LettingUnitBookings | ALL | NULL | NULL | NULL | NULL | 3 | |
| 6 | UNION | LettingUnitBookings | index | NULL | F_LU_ID | 8 | NULL | 3 | Using index |
| NULL | UNION RESULT | <union5,6> | ALL | NULL | NULL | NULL | NULL | NULL | |
| 3 | DERIVED | LettingUnitBookings | ALL | NULL | NULL | NULL | NULL | 3 | |
| 4 | UNION | LettingUnitBookings | index | NULL | F_LU_ID | 8 | NULL | 3 | Using index |
| NULL | UNION RESULT | <union3,4> | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+---------------------+--------+---------------+---------+---------+------+------+---------------------------------+
Secara umum, Anda ingin menghindari rencana pengoptimalan yang memaksa Using filesort
atau Using temporary
karena ini adalah pembunuh kinerja. Kueri menggunakan GROUP BY
hampir pasti menyebabkan pengoptimalan semacam ini, setidaknya di MySQL.