View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 20653 | Bug reports | Speed optimization | public | 2026-08-14 11:18 | 2026-08-14 14:19 |
| Reporter | sigun | Assigned To | |||
| Priority | none | Severity | minor | ||
| Status | new | Resolution | open | ||
| Product Version | 7.0.x | ||||
| Summary | 20653: Listing submitted responses for surveys take LOTS of time | ||||
| Description | Browsing survey responses (Responses → Browse responses) is extremely slow for surveys with a non-trivial number of questions and responses, because | ||||
| Steps To Reproduce | Steps to reproduce
Actual behaviorLoading a single page of 10 responses took ~3 seconds, and the general query log showed the query
executed 526 times for that one page load (once per non-empty answer cell), each time loading every question row for the survey, only to run:
i.e. a linear scan just to decide whether Expected behaviorThe responses grid should not re-run survey-wide queries once per cell. Rendering N rows × M columns should cost O(1) (or at most O(rows)) survey/question metadata queries, not O(rows × cols). Root cause
Patch example code provided, the performance regression is fixed on our local installation. | ||||
| Tags | No tags attached. | ||||
| Attached Files | fix-getExtendedAnswer-n-plus-one.patch (1,787 bytes)
diff --git a/application/helpers/common_helper.php b/application/helpers/common_helper.php
--- a/application/helpers/common_helper.php
+++ b/application/helpers/common_helper.php
@@ -1000,16 +1000,24 @@ function getExtendedAnswer($iSurveyID, $sFieldCode, $sValue, $sLanguage, $ques
if ($sValue == null || $sValue == '') {
return '';
}
- $survey = Survey::model()->findByPk($iSurveyID);
- $rawQuestions = Question::model()->findAll("sid = :sid", [":sid" => $iSurveyID]);
- $found = false;
- foreach ($rawQuestions as $rawQuestion) {
- $found = $found || (strpos($sFieldCode, "Q{$rawQuestion->qid}") === 0);
+ // createFieldMap() is cached per survey/language in the user session, but
+ // Survey::model()->findByPk() is not - cache it per request (keyed off the
+ // current Yii app instance, which is recreated fresh for every request) so
+ // that rendering many cells of the same survey (e.g. the responses grid)
+ // doesn't re-fetch the survey row for every single cell.
+ static $surveyCache = [];
+ $appId = spl_object_id(Yii::app());
+ if (!isset($surveyCache[$appId])) {
+ $surveyCache = [$appId => []];
}
+ if (!array_key_exists($iSurveyID, $surveyCache[$appId])) {
+ $surveyCache[$appId][$iSurveyID] = Survey::model()->findByPk($iSurveyID);
+ }
+ $survey = $surveyCache[$appId][$iSurveyID];
+
//Fieldcode used to determine question, $sValue used to match against answer code
//Returns NULL if question type does not suit
- if ($found) {
- //Only check if it looks like a real fieldcode
+ {
$fieldmap = createFieldMap($survey, 'short', false, false, $sLanguage);
if (isset($fieldmap[$sFieldCode])) {
$fields = $fieldmap[$sFieldCode];
| ||||
| Bug heat | 4 | ||||
| Complete LimeSurvey version number (& build) | 7.0.10+260813 | ||||
| I will donate to the project if issue is resolved | No | ||||
| Story point estimate | 0 | ||||
| Browser | Any | ||||
| Database type & version | MySQL 8.0.46 | ||||
| Server OS (if known) | Ubuntu 24.04 | ||||
| Webserver software & version (if known) | nginx + php-fpm | ||||
| PHP Version | 8.3 | ||||
|
The issue Before only check if it's start by surveyId. Unsure if it's OK to remove it, but surely more quick :) |
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-08-14 11:18 | sigun | New Issue | |
| 2026-08-14 11:18 | sigun | File Added: fix-getExtendedAnswer-n-plus-one.patch | |
| 2026-08-14 14:08 | DenisChenu | Issue Monitored: DenisChenu | |
| 2026-08-14 14:08 | DenisChenu | Bug heat | 0 => 2 |
| 2026-08-14 14:19 | DenisChenu | Note Added: 85474 | |
| 2026-08-14 14:19 | DenisChenu | Bug heat | 2 => 4 |