Lots of improvements possible:
- Firstly, let's talk about the outer query (main SELECT query) on the oc_subjecttable. This query can take the benefit ofORDER BYOptimization by using the composite index:(status, created). So, define the following index (if not defined already):
ALTER TABLE oc_subject ADD INDEX (status, created);
- Secondly, your subquery to get Count is not Sargeable, because of using Date()function on the column insideWHEREclause. Due to this, it cannot use indexes properly.
Also, DATE(oc_details.created) > DATE(NOW() - INTERVAL 1 DAY) simply means that you are trying to consider those details which are created on the current date (today). This can be simply written as: oc_details.created >= CURRENT_DATE . Trick here is that even if created column is of datetime type, MySQL will implictly typecast the CURRENT_DATE value to CURRENT_DATE 00:00:00. 
So change the inner subquery to as follows:
SELECT COUNT(sid) 
FROM oc_details 
WHERE oc_details.created >= CURRENT_DATE
      AND oc_details.sid = oc_subject.id
- Now, all the improvements on inner subquery will only be useful when you have a proper index defined on the oc_detailstable. So, define the following Composite (and Covering) Index on theoc_detailstable:(sid, created). Note that the order of columns is important here becausecreatedis a Range condition, hence it should appear at the end. So, define the following index (if not defined already):
ALTER TABLE oc_details ADD INDEX (sid, created);
- Fourthly, in case of multi-table queries, it is advisable to use Aliasing, for code clarity (enhanced readability), and avoiding unambiguous behaviour.
So, once you have defined all the indexes (as discussed above),  you can use the following query: 
SELECT s.*, 
      (SELECT COUNT(d.sid) 
       FROM oc_details AS d
       WHERE d.created >= CURRENT_DATE
             AND d.sid = s.id) as totalDetails 
FROM oc_subject AS s
WHERE s.status='1' 
ORDER BY s.created DESC LIMIT " . (int)$start . ", " . (int)$limit;