MYSQL Query Index Check
I have an interesting idea for you.

Create the following indexes

ALTER TABLE operations
    ADD INDEX `date_zoneId_statusId_ndx`    (`date`,`zoneId`,`statusId`)
   ,ADD INDEX `date_machineId_statusId_ndx` (`date`,`machineId`,`statusId`)
   ,ADD INDEX `date_shiftId_statusId_ndx`   (`date`,`shiftId`,`statusId`)
   ,ADD INDEX `zoneId_statusId_date_ndx`    (`zoneId`,`statusId`,`date`)
   ,ADD INDEX `machineId_statusId_date_ndx` (`machineId`,`statusId`,`date`)
   ,ADD INDEX `shiftId_statusId_date_ndx`   (`shiftId`,`statusId`,`date`)
;


You could then evaluate your queries by running:

EXPLAIN SELECT zoneId, statusId, COUNT(*) as intervals 
FROM `operations` 
WHERE (`date` &gt; 'XXXX-XX-XX' AND `date` &lt;= 'XXXX-XX-XX') 
GROUP BY `zoneId`,`statusId` 
ORDER BY NULL\G

EXPLAIN SELECT machineId, statusId, COUNT(*) as intervals 
FROM `operations` 
WHERE (`date` &gt; 'XXXX-XX-XX' AND `date` &lt;= 'XXXX-XX-XX') GROUP BY `machineId`,`statusId` 
ORDER BY NULL\G

EXPLAIN SELECT shiftId, statusId, COUNT(*) as intervals 
FROM `operations` 
WHERE (`date` &gt; 'XXXX-XX-XX' AND `date` &lt;= 'XXXX-XX-XX') 
GROUP BY `shiftId`,`statusId` 
ORDER BY NULL\G


The output from each EXPLAIN will plainly tell you which index.

It will also show the least number of steps the Query Optimizer will take.

My guess is that the indexes with the date column last will be selected. An exception may be a small date range which may favor the indexes with the date column first. In that instance, you would want to keep all 6 indexes.

The indexes with the date column last would be used by the GROUP BY so that no temp table sorting would be necessary.

WARNING ON HAVE MANY INDEXES : Bulk INSERT performance would suffer due to managing multiple covering indexes, but SELECT performance would improve greatly. Dropping unnecessary indexes becomes a necessity.