Optimise Date Related query with Create Dates

I have below query that takes about 9.8 seconds, I like to know is there a way to optimize the query with indexes,

I already have an index on 'uc.recieved_date'

other than this I don't what else I can do to optimize the SQL selection, There is no way to break it down to smaller portions with LIMIT as it's a graph.

SELECT (count(*)-1) AS total, a.Date AS created_dates
                    FROM
                    (
                            SELECT (CURDATE() - INTERVAL c.number DAY) AS date
                            FROM (SELECT singles + tens + hundreds number FROM 
                            ( SELECT 0 singles
                            UNION ALL SELECT   1 UNION ALL SELECT   2 UNION ALL SELECT   3
                            UNION ALL SELECT   4 UNION ALL SELECT   5 UNION ALL SELECT   6
                            UNION ALL SELECT   7 UNION ALL SELECT   8 UNION ALL SELECT   9
                            ) singles JOIN 
                            (SELECT 0 tens
                            UNION ALL SELECT  10 UNION ALL SELECT  20 UNION ALL SELECT  30
                            UNION ALL SELECT  40 UNION ALL SELECT  50 UNION ALL SELECT  60
                            UNION ALL SELECT  70 UNION ALL SELECT  80 UNION ALL SELECT  90
                            ) tens  JOIN 
                            (SELECT 0 hundreds
                            UNION ALL SELECT  100 UNION ALL SELECT  200 UNION ALL SELECT  300
                            UNION ALL SELECT  400 UNION ALL SELECT  500 UNION ALL SELECT  600
                            UNION ALL SELECT  700 UNION ALL SELECT  800 UNION ALL SELECT  900
                            ) hundreds
                            ORDER BY number DESC) c  
                            WHERE c.number BETWEEN 0 and 364            
                    ) a
                    LEFT OUTER JOIN `usr_count` uc
                    ON DATE(uc.received_on) = a.Date
                    WHERE
                        a.Date  BETWEEN CURDATE() - INTERVAL 28 DAY AND CURDATE() GROUP BY a.Date
                   ORDER BY a.Date ASC

  • Build a permanent table of "numbers". (The 'cross-join' you have takes some time.)

  • Have PRIMARY KEY(number) on that table. (Needed for the WHERE and ORDER BY)

  • Consider switching to MariaDB, which has the pseudo table seq_0_to_999 to provide "numbers" instantly.

  • Since you have a LEFT JOIN, don't you need AND ... IS [NOT] NULL? (Else make it INNER JOIN.)

  • ON DATE(uc.received_on) = a.Date may be terribly inefficient. (See "sargable".) A possible fix is

      ON uc.received_on >= a.Date
     AND uc.received_on  < a.Date + INTERVAL 1 DAY
    

Do some of those, then come back for more suggestions.