I have the following 3 tables, and I don't have the option to modify them.
[Logs]table with[log_type],[log_time],[log_data], and other irrelevant columns[Places]table with[name],[place_index], and other irrelevant columns[Addresses]table with[place_index],[road_0], ...,[road_15], and other irrelevant columns
Logs of [log_type] 12 or 15 has one of the roads in the [Addresses] table in [log_data]; logs of [log_type] 1 has one of the names from [Places] table; logs of [log_type] 7 is similar to type 1 but with a space and some other info after the name.
What the query has to do is to select a list of "12" or "15" logs which
- does not have a "1" log before it, which corresponds to a place (log_data) containing its corresponding road.
 
or
- has the "1" log before it but with a "7" log in between, which also corresponds to the same place.
 
For example,
assuming Road_X is in PlaceI, Road_Y is in PlaceJ, and Road_Ex, Road_Z are in PlaceK, and given the following table.
--------------------------------------------
| id | log_type |  log_time  | log_data    |
--------------------------------------------
| 1  |    7     | 2018-01-30 |  PlaceA 2.3 |
--------------------------------------------
| 2  |    1     | 2018-01-30 |  PlaceB     |
--------------------------------------------
| 3  |    12    | 2018-01-31 |  Road_Ex    |
--------------------------------------------
| 4  |    7     | 2018-02-01 |  PlaceB 2.5 |
--------------------------------------------
| 5  |    7     | 2018-02-01 |  PlaceI 2.7 |
--------------------------------------------
| 6  |    15    | 2018-02-02 |  Road_X     |
--------------------------------------------
| 7  |    1     | 2018-02-04 |  PlaceI     |
--------------------------------------------
| 8  |    1     | 2018-02-05 |  PlaceJ     |
--------------------------------------------
| 9  |    12    | 2018-02-06 |  Road_X     |
--------------------------------------------
| 10 |    15    | 2018-02-06 |  Road_Y     |
--------------------------------------------
| 11 |    1     | 2018-02-10 |  PlaceK     |
--------------------------------------------
| 12 |    12    | 2018-02-11 |  Road_Z     |
--------------------------------------------
| 13 |    12    | 2018-02-11 |  Road_Ex    |
--------------------------------------------
| 14 |    7     | 2018-02-12 |  PlaceI 2.7 |
--------------------------------------------
| 15 |    7     | 2018-02-12 |  PlaceJ 2.8 |
--------------------------------------------
| 16 |    12    | 2018-02-17 |  Road_X     |
--------------------------------------------
| 17 |    15    | 2018-02-18 |  Road_Y     |
--------------------------------------------
The query should return rows 3, 6, 16, 17.
This is the best I could come up with so far:
declare @since datetimeoffset
set @since = '2018-02-10-05:00'
select a.[log_type], a.[log_time], a.[log_data]
from 
    (select [log_type], [log_data], [log_time],
        (select [name] 
         from [Places]
         where [place_index] =
            (select [place_index] 
             from [Addresses] 
             where [log_data] in 
                ([road_0], [road_1], [road_2], [road_3], [road_4], 
                    [road_5], [road_6], [road_7], [road_8], [road_9],
                    [road_10], [road_11], [road_12], [road_13], [road_14], 
                    [road_15]))) as [place_name]
     from [Logs]
     where [log_type] in (12, 15) and [log_time] >= @since) a
outer apply 
    (select TOP 1 [log_data] from 
        (select TOP 1 [log_data], [log_time]
         from [Logs]
         where [log_type] = 1 and [log_data] = [place_name] 
            and [log_time] >= @since and [log_time] < a.[log_time]
         order by [log_time] desc
         UNION ALL
         (select TOP 1 NULL, [log_time]
          from [Logs]
          where [log_type] = 7 and LEFT([log_data], CHARINDEX(' ', [log_data]) - 1) = [place_name] 
          and [log_time] >= @since and [log_time] < a.[log_time]
          order by [log_time] desc)) i
     order by [log_time] desc) b
where b.[log_data] is null
order by a.[log_time] desc
Note that because I need to reference [place_name] from table a in the subquery, I had to use outer apply instead of left join. However, it takes 5 seconds to generate less than 40 records from around 30k records in [Logs]. I've also tried replacing outer apply with where, but there's no notable difference.
Can the query be further optimized or will I need to move this business logic to the service that sends this query?
EDIT
DDL for the tables (only including relevant columns):
CREATE TABLE [Logs](
    [log_time] [datetimeoffset](7) NOT NULL, -- indexed
    [log_type] [int] NULL,
    [log_data] [varchar](300) NULL
)
CREATE TABLE [Places](
    [place_index] [smallint] NOT NULL,       -- PK, indexed
    [name] [nchar](253) NULL
)
CREATE TABLE [Addresses](
    [place_index] [smallint] NOT NULL,       -- PK, indexed
    [road_0] [char](32) NULL,
    [road_1] [char](32) NULL,
    [road_2] [char](32) NULL,
    [road_3] [char](32) NULL,
    [road_4] [char](32) NULL,
    [road_5] [char](32) NULL,
    [road_6] [char](32) NULL,
    [road_7] [char](32) NULL,
    [road_8] [char](32) NULL,
    [road_9] [char](32) NULL,
    [road_10] [char](32) NULL,
    [road_11] [char](32) NULL,
    [road_12] [char](32) NULL,
    [road_13] [char](32) NULL,
    [road_14] [char](32) NULL,
    [road_15] [char](32) NULL
)