I don't see a lot of opportunity for improvement.
The index you added was probably a big help, because it's being used for the range matching on the WHERE clause (type => range, key => tran_date), and it's being used as a covering index (extra => using index), avoiding the need to seek into the table to fetch the row data.
But since you're using functions to construct the financial_year value for the group by, both the "using filesort" and "using temporary" can't be avoided. But, those aren't the real problem. The real problem is that you're evaluating MONTH(tran_date) 346,485 times and YEAR(tran_date) at least that many times... ~700,000 function calls in one second doesn't seem too bad.
Plan B: I am definitely not a fan of storing redundant data, and I'm dead-set against making the application responsible for maintaining it... but one option I might be tempted to try would be to create a dashboard_stats_by_financial_year table, and use after-insert/update/delete triggers on the transactions1 table to manage keeping those stats current.
That option has a cost, of course -- adding to the amount of time it takes to update/insert/delete a transaction... but, waiting > 1200 milliseconds for stats for your dashboard is a cost, too. So it may come down to whether you want to pay for it now or pay for it later.
You can use conditional sum for this calculation something as
select
date_format(created,'%d-%m') as created_date ,
sum( case when status='open' then 1 else 0 end )+
sum( case when status='new' then 1 else 0 end )+
sum( case when status='resolved' and date(resolved) > date(created) then 1 else 0 end ) as open
from table_name
where
YEAR(Created) = '2015'
group by created_date ;
Here is a test case
mysql> select * from test ;
+------+---------------------+---------------------+----------+
| id | created | resolved | status |
+------+---------------------+---------------------+----------+
| 1 | 2015-05-10 00:00:00 | 1970-01-01 00:00:00 | open |
| 2 | 2015-05-10 00:00:00 | 1970-01-01 00:00:00 | new |
| 3 | 2015-05-10 00:00:00 | 2015-05-12 00:00:00 | resolved |
| 4 | 2015-05-11 00:00:00 | 1970-01-01 00:00:00 | open |
| 5 | 2015-05-11 00:00:00 | 1970-01-01 00:00:00 | new |
| 6 | 2015-05-11 00:00:00 | 2015-05-11 00:00:00 | resolved |
+------+---------------------+---------------------+----------+
6 rows in set (0.00 sec)
mysql> select
-> date_format(created,'%d-%m') as created_date ,
-> sum( case when status='open' then 1 else 0 end )+
-> sum( case when status='new' then 1 else 0 end )+
-> sum( case when status='resolved' and date(resolved) > date(created) then 1 else 0 end ) as open
-> from test
-> where
-> YEAR(Created) = '2015'
-> group by created_date ;
+--------------+------+
| created_date | open |
+--------------+------+
| 10-05 | 3 |
| 11-05 | 2 |
+--------------+------+
2 rows in set (0.00 sec)
UPDATE
The count of open is a incremental as per the comment. So the following should do the trick
select
created_date,
@open:= @open+open_ticket-resolved as open
from(
select
date_format(created,'%d-%m') as created_date ,
sum( case when status='open' then 1 else 0 end )+
sum( case when status='new' then 1 else 0 end )+
sum( case when status='resolved' and ( date(resolved) > date(created) or date(resolved) = date(created)) then 1 else 0 end ) as open_ticket,
sum(case when status = 'resolved' and date(resolved) = date(created) then 1 else 0 end) as resolved
from test
where
YEAR(Created) = '2015'
group by created_date
)x,(select @open:=0)r order by created_date ;
From the above sample data it will have
+--------------+------+
| created_date | open |
+--------------+------+
| 10-05 | 3 |
| 11-05 | 5 |
+--------------+------+
UPDATE:
Count the previous tickets which got resolved on a given date and deduct that from the current day open ticket, for that you need a left join
something as
select
created_date,
@open:= @open+open_ticket-resolved_ticket as open
from(
select
date_format(t.created,'%d-%m') as created_date ,
sum( case when t.status='open' then 1 else 0 end )+
sum( case when t.status='new' then 1 else 0 end )+
sum( case when t.status='resolved' and ( date(t.resolved) > date(created) or date(t.resolved) = date(created)) then 1 else 0 end ) as open_ticket,
coalesce(tot,0) as resolved_ticket
from test t left join(
select count(*) as tot, date(resolved) as resolved from test where status='resolved' group by date(resolved)
)x on date(x.resolved) = date(t.created)
where
YEAR(t.created) = '2015'
group by created_date
)x,(select @open:=0)r order by created_date ;
OUTPUT :
+--------------+------+
| created_date | open |
+--------------+------+
| 10-05 | 3 |
| 11-05 | 5 |
| 12-05 | 7 |
+--------------+------+
Best Answer
MySQL works like you expected and it should return 1.
dbfiddle: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=4fd6a3744a042c376880f030f4d12101