diff --git a/db/migrations/5.5.28_biest3893_performance_calendar.php b/db/migrations/5.5.28_biest3893_performance_calendar.php
new file mode 100644
index 0000000000000000000000000000000000000000..82a86fecbe5cb8bdd132660e9683aeb11fb4685d
--- /dev/null
+++ b/db/migrations/5.5.28_biest3893_performance_calendar.php
@@ -0,0 +1,25 @@
+<?php
+
+final class Biest3893PerformanceCalendar extends Migration
+{
+    public function description()
+    {
+        return 'add index to calendar tables';
+    }
+
+    public function up()
+    {
+        $db = DBManager::get();
+        $db->exec("DELETE FROM `calendar_date_exceptions` WHERE `date` = '1970-01-01'");
+        $db->exec("ALTER TABLE `calendar_date_exceptions` ADD INDEX(`calendar_date_id`)");
+        $db->exec("ALTER TABLE `calendar_dates` ADD INDEX `repetition_type` (`repetition_type`, `repetition_end`)");
+        $db->exec("ALTER TABLE `calendar_dates` ADD INDEX `begin` (`begin`)");
+        try {
+            $db->exec("ALTER TABLE `calendar_dates` DROP INDEX `uid`");
+        } catch (PDOException $exception) {}
+    }
+
+    public function down()
+    {
+    }
+}
diff --git a/lib/models/calendar/CalendarDateAssignment.class.php b/lib/models/calendar/CalendarDateAssignment.class.php
index 18cd6101cb39502e1f058e7c069e8523c05e76d6..fbd21a7d9475bdefd70b7308622dc8cca21b38f6 100644
--- a/lib/models/calendar/CalendarDateAssignment.class.php
+++ b/lib/models/calendar/CalendarDateAssignment.class.php
@@ -232,29 +232,35 @@ class CalendarDateAssignment extends SimpleORMap implements Event
         $sql = "JOIN `calendar_dates`
             ON calendar_date_id = `calendar_dates`.`id`
             WHERE
-            `calendar_date_assignments`.`range_id` = :range_id ";
+            `calendar_date_assignments`.`range_id` = :range_id
+            AND
+            `access` IN ( :access_levels ) ";
         if (!$with_declined) {
             $sql .= "AND `calendar_date_assignments`.`participation` <> 'DECLINED' ";
         }
-        $sql .= "AND (
-                `calendar_dates`.`begin` BETWEEN :begin AND :end
-                OR
-                (`calendar_dates`.`begin` <= :end AND `calendar_dates`.`repetition_type` <> ''
-                    AND `calendar_dates`.`repetition_end` > :begin)
-                OR
-                :begin BETWEEN `calendar_dates`.`begin` AND `calendar_dates`.`end`
-            )
-            AND
-            `access` IN ( :access_levels )
-            ORDER BY `calendar_dates`.`begin` ASC";
+        $sql_single = $sql . " AND
+                `calendar_dates`.`begin` < :end  AND :begin < `calendar_dates`.`end`
+            ";
 
-        $events = self::findBySql($sql, [
+        $events = self::findBySql($sql_single, [
             'range_id'      => $range_id,
             'begin'         => $begin->getTimestamp(),
             'end'           => $end->getTimestamp(),
             'access_levels' => $access_levels
         ]);
 
+
+        $sql_repetition = $sql . " AND `calendar_dates`.`begin` < :end AND `calendar_dates`.`repetition_type` IN ('DAYLY', 'WEEKLY', 'MONTHLY', 'YEARLY')
+                    AND `calendar_dates`.`repetition_end` > :begin
+            ";
+
+        $events = array_merge($events, self::findBySql($sql_repetition, [
+            'range_id'      => $range_id,
+            'begin'         => $begin->getTimestamp(),
+            'end'           => $end->getTimestamp(),
+            'access_levels' => $access_levels
+        ]));
+
         $m_start = clone $begin;
         $m_end = clone $end;
         $events_created = [];