Searching for availability with MySQL (and PHP)?

前端 未结 2 1377
别跟我提以往
别跟我提以往 2020-12-30 17:23

I have two MySQL (MyIsAm) tables that represent letting units and bookings:

  • LettingUnits (ID, Name, etc...)
  • LettingUnitBooki
2条回答
  •  忘掉有多难
    2020-12-30 18:09

    Here's a solution that seems to work:

    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;
    

    The output is:

    +-----+-------------+-------------------+-----------------+-----------------+
    | 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 |
    +-----+-------------+-------------------+-----------------+-----------------+
    

    Analyzing this with EXPLAIN shows that it employs indexes pretty well:

    +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
    | id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows | Extra                   |
    +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
    |  1 | PRIMARY     |  | 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 |                         |
    +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
    

    Compare with the EXPLAIN report for the solution given by @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      |           | ALL    | NULL          | NULL    | NULL    | NULL |    4 | Using where                     |
    |  2 | DERIVED      |           | ALL    | NULL          | NULL    | NULL    | NULL |    4 | Using temporary; Using filesort |
    |  2 | DERIVED      |           | 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 |           | 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 |           | ALL    | NULL          | NULL    | NULL    | NULL | NULL |                                 |
    +----+--------------+---------------------+--------+---------------+---------+---------+------+------+---------------------------------+
    

    In general, you want to avoid optimization plans that force Using filesort or Using temporary because these are performance killers. A query using GROUP BY is almost certain to cause this kind of optimization, at least in MySQL.

提交回复
热议问题