Reputation: 8349
I have a MySQL query which is used to determine if a piece of equipment, which there are only 3 of, is being used by four concurrent events at once. I have a working query, but it seems inefficient and I am curious if there is a better way to do the select.
Table structure (columns not relevant to the query have been removed) The table currently contains around 7-8k rows.
CREATE TABLE IF NOT EXISTS `tc_event` (
`WorkOrderNumber` int(11) NOT NULL DEFAULT '0',
`EventName` varchar(120) DEFAULT NULL,
`CrewStartTime` datetime DEFAULT NULL,
`CrewEndTime` datetime DEFAULT NULL,
`SoundConsole` varchar(30) DEFAULT NULL,
`Canceled` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`WorkOrderNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Current (working) query:
SELECT UNIX_TIMESTAMP(T1.CrewStartTime) AS ConflictDate
FROM tc_event T1, tc_event T2, tc_event T3, tc_event T4
WHERE
(T1.CrewStartTime BETWEEN T2.CrewStartTime AND T2.CrewEndTime)
AND (T1.CrewStartTime BETWEEN T3.CrewStartTime AND T3.CrewEndTime)
AND (T1.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
AND (T2.CrewSTartTime BETWEEN T3.CrewStartTime AND T3.CrewEndTime)
AND (T2.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
AND (T3.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
AND T1.WorkOrderNumber != T2.WorkOrderNumber
AND T1.WorkOrderNumber != T3.WorkOrderNumber
AND T1.WorkOrderNumber != T4.WorkOrderNumber
AND T2.WorkOrderNumber != T3.WorkOrderNumber
AND T2.WorkOrderNumber != T4.WorkOrderNumber
AND T3.WorkOrderNumber != T4.WorkOrderNumber
AND T1.CrewStartTime > NOW()
AND T1.SoundConsole = '12-Chan/PA-12'
AND T2.SoundConsole = '12-Chan/PA-12'
AND T3.SoundConsole = '12-Chan/PA-12'
AND T4.SoundConsole = '12-Chan/PA-12'
AND (T1.Canceled = 0 AND T1.EventName NOT LIKE '%*NOTC*%')
AND (T2.Canceled = 0 AND T2.EventName NOT LIKE '%*NOTC*%')
AND (T3.Canceled = 0 AND T3.EventName NOT LIKE '%*NOTC*%')
AND (T4.Canceled = 0 AND T4.EventName NOT LIKE '%*NOTC*%')
GROUP BY DATE(T1.CrewStartTime)
ORDER BY T1.CrewStartTime
Query EXPLAIN statement:
Upvotes: 1
Views: 60
Reputation: 1269443
You just want to know if there is a conflict, which is 4 users at the same time. For this, you can just look at the event start time and check how many concurrent events there are:
select soundconsole, st.CrewStartTime, count(*)
from (select distinct CrewStartTime, soundconsole
from tc_event
) st join
tc_event e
on st.CrewStratTime between e.CrewStartTime and e.CrewEndTime and
st.soundconsole = e.soundconsole
group by st.CrewStartTime, tc.soundconsole
having count(*) >= 4
Upvotes: 1
Reputation: 80011
Start with changing the inequalities to less than/greater than comparisons. That simplifies things a lot as well:
SELECT UNIX_TIMESTAMP(T1.CrewStartTime) AS ConflictDate
FROM tc_event T1, tc_event T2, tc_event T3, tc_event T4
WHERE
(T1.CrewStartTime BETWEEN T2.CrewStartTime AND T2.CrewEndTime)
AND (T2.CrewSTartTime BETWEEN T3.CrewStartTime AND T3.CrewEndTime)
AND (T3.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
AND T1.WorkOrderNumber < T2.WorkOrderNumber
AND T2.WorkOrderNumber < T3.WorkOrderNumber
AND T3.WorkOrderNumber < T4.WorkOrderNumber
AND T1.CrewStartTime > NOW()
AND T1.SoundConsole = '12-Chan/PA-12'
AND T2.SoundConsole = '12-Chan/PA-12'
AND T3.SoundConsole = '12-Chan/PA-12'
AND T4.SoundConsole = '12-Chan/PA-12'
AND (T1.Canceled = 0 AND T1.EventName NOT LIKE '%*NOTC*%')
AND (T2.Canceled = 0 AND T2.EventName NOT LIKE '%*NOTC*%')
AND (T3.Canceled = 0 AND T3.EventName NOT LIKE '%*NOTC*%')
AND (T4.Canceled = 0 AND T4.EventName NOT LIKE '%*NOTC*%')
GROUP BY DATE(T1.CrewStartTime)
ORDER BY T1.CrewStartTime
After that you would do good to add an index on CrewStartTime
, that should help quite a bit in performance. Indexes on other columns which you filter by could also be helpful.
Upvotes: 1