Я могу решить эту проблему с помощью нескольких операторов foreach, но загрузка страницы занимает целую вечность, когда в каждом классе 26 учеников, а у некоторых предметов до 13 ’radnummer’. См. Примеры ниже.
Это то, что я предпочитаю выводить (строки и столбцы):

Проблема: загружается вечно.
Вопрос: как мне его ускорить и сделать более эффективным?
Таблица первая, в которой я выбираю всех учеников в классе (ВЫБРАТЬ 1):
SELECT `intressenter_alla`.id, `intressenter_alla`.fornamn, `intressenter_alla`.efternamn
FROM `intressenter_alla`
INNER JOIN `klass_elev`
ON `intressenter_alla`.id = `klass_elev`.id
WHERE (`klass_elev`.klass = :klassen)
ORDER BY `intressenter_alla`.efternamn, `intressenter_alla`.fornamn ASC
PRINT_R дает:
Array (
[0] => Array (
[id] => 1226
[0] => 1226
[lid] => 0
[1] => 0
[fornamn] => Peter
[2] => Peter
[efternamn] => Strobe
[3] => Strobe
[personnr] => 070920-8690
[4] => 070920-8690
[mejl] => [email protected]
[5] => [email protected]
[6] => 1226
[klass] => 6B
[7] => 6B
)
[1] => Array (
[id] => 1227
[0] => 1227
[lid] => 0
[1] => 0
[fornamn] => Victor
[2] => Victor
[efternamn] =>Gand
[3] => Gand
[personnr] => 070518-8995
[4] => 070518-8995
[mejl] => [email protected]
[5] => [email protected]
[6] => 1227
[klass] => 6B
[7] => 6B
)
)
Таблица 2, где я выбираю соответствующие данные для каждого студента. Вот тут проблема. В этом примере у каждого студента должно быть пять строк 'radnummer' (см. Ниже) для этого конкретного предмета. Появляется только последний. В каждой строке должно отображаться определенное значение kunsk_klick. См. Пример ниже (ВЫБРАТЬ 2):
SELECT *
FROM `iup_kunskapskrav_klick`
WHERE elev_id = ? AND radnummer = ? AND amne_id = ? AND arskurs = ?
ORDER BY radnummer, datum DESC
PRINT_R дает:
Array (
[kunsk_id] => 138557
[0] => 138557
[amne_id] => 1
[1] => 1
[radnummer] => 5
[2] => 5
[elev_id] => 1226
[3] => 1226
[arskurs] => 5
[4] => 5
[lid] => 1
[5] => 1
[kunsk_klick] => E
[6] => E
[datum] => 2018-05-29
[7] => 2018-05-29
)
Array (
[kunsk_id] => 138561
[0] => 138561
[amne_id] => 1
[1] => 1
[radnummer] => 5
[2] => 5
[elev_id] => 1227
[3] => 1227
[arskurs] => 5
[4] => 5
[lid] => 1
[5] => 1
[kunsk_klick] => E
[6] => E
[datum] => 2018-05-29
[7] => 2018-05-29
)
РЕДАКТИРОВАТЬ 1: структура таблиц.
Стол intressenter_alla
CREATE TABLE `intressenter_alla` (
`id` int(4) NOT NULL,
`lid` int(3) NOT NULL,
`fornamn` varchar(255) NOT NULL,
`efternamn` varchar(255) NOT NULL,
`personnr` varchar(12) NOT NULL,
`mejl` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Стол iup_kunskapskrav_klick
CREATE TABLE `iup_kunskapskrav_klick` (
`kunsk_id` int(11) UNSIGNED NOT NULL,
`amne_id` int(3) NOT NULL,
`radnummer` int(10) NOT NULL,
`elev_id` int(3) NOT NULL,
`arskurs` int(2) NOT NULL,
`lid` int(3) NOT NULL,
`kunsk_klick` varchar(3) COLLATE utf8_swedish_ci NOT NULL,
`datum` date NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;
Стол klass_elev
CREATE TABLE `klass_elev` (
`id` int(5) NOT NULL,
`klass` varchar(2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Elevid och klass.';
Обновлено еще раз: пример кода (я знаю, плохое смешивание PHP и HTML, а также плохие отступы ...).
<?php
// All students (See SELECT number 1)
$hamta_hela_klassen = $anvandare->klasslista($_GET['klass']);
// Count how many radnummer there is in the subject
$count = 0;
$count = $abb->rakna_kunskapskrav($_GET['amne_id'], $arskursens);
echo "<table>";
echo "<thead>";
echo "<tr><th>Nr.</th><th>Picture</th><th>Name</th>";
if ($count<=1){
echo "<th scope='row' style='vertical-align:middle;text-align:center'>Kunskapskrav</th>";
} else {
for($i=1;$i<=$count;$i++)
{
// This outputs R1 - R2 and so on in the header of the columns (see the picture above)
echo "<th width='1%' scope='row' style='vertical-align:middle;text-align:center'>R".$i."</th>";
}
}
echo "<th>Date</th><th>Button</th>";
$raknare = 0;
// Loop out each student. Not the most effective way...
foreach ($hamta_hela_klassen as $klassuppgifter){
$raknare++;
// Profile picture
$profilbild = '/home/jo/public_html/no/students/profilbilder/'.$klassuppgifter['id'].'.jpg';
echo "<td>";
echo AKTIV_URL."students/profilbilder/".$klassuppgifter['id'].".jpg";
echo "</td>";
// NAME
echo "<td>";
echo $klassuppgifter['fornamn']." ".$klassuppgifter['efternamn'];
echo "</td>";
if ($count<=1){
echo "<td>Empty.</td>";
} else {for($i=1;$i<=$count;$i++)
{
// Fetching each corresponding RADNUMMER for each student (see SELECT 2 above)
$iup_info_k1 = $iup->hamta_ett_kunskapskrav_klick_klass($klassuppgifter['id'], $i,$_GET['amne_id'], $arskursen);
if (empty($iup_info_k1) && ($arskursen == '5' || $arskursen =='6' || $arskursen =='8' || $arskursen =='9')){
$arskursen_lager = $arskursen -1;
$iup_info = $iup->hamta_ett_kunskapskrav_klick_klass($klassuppgifter['id'], $i,$_GET['amne_id'], $arskursen_lager);
} else {
$iup_info = $iup_info_k1;
}
//Special for students in 4 - 5
if ($arskursen=='4' || $arskursen=='5') {
if ($iup_info['kunsk_klick'] == "G"){$betyget = 'P';}
if ($iup_info['kunsk_klick'] == "F"){$betyget = 'O';}
elseif ($iup_info['kunsk_klick'] == "E"){$betyget = '1';}
elseif ($iup_info['kunsk_klick'] == "C"){$betyget = '2';}
elseif ($iup_info['kunsk_klick'] == "A"){$betyget = '3';}
elseif (empty($iup_info['kunsk_klick'])) {$betyget = "P"; }
}
//Special for students in 6 - 9
if ($arskursen=='6' || $arskursen=='7' || $arskursen=='8' || $arskursen=='9') {
if ($iup_info['kunsk_klick'] == "G"){$betyget = 'P';}
elseif (empty($iup_info['kunsk_klick'])) {$betyget = "P"; }
else { $betyget = $iup_info['kunsk_klick']; }
}
echo "<td>".$betyget."</td>";
}
}
// DATE
echo "<td>";
echo $iup_info['datum'];
echo "</td>";
// Edit button
echo "<td>";
echo "EDIT";
echo "</td>";
}
echo "</tr>";
echo "</tbody>";
echo "</table>";
?>
Изменить 3:
Чтобы ТОЛЬКО выводил данные столбца названный, а не числовые данные, я меняю оператор выборки:
$ pdo-> fetchAll (PDO :: FETCH_ASSOC);
Теперь это выглядит так:
Array (
[kunsk_id] => 138561
[amne_id] => 1
[radnummer] => 5
[elev_id] => 1227
[arskurs] => 5
[lid] => 1
[kunsk_klick] => E
[datum] => 2018-05-29
)
Очень сложно следить за вопросом, не зная схемы базы данных. Не могли бы вы реплицировать базу данных, например, в SQL Fiddle (sqlfiddle.com)?
... или еще лучше, добавьте схему здесь, на SO (чтобы будущие посетители также могли ее видеть).
@MagnusEriksson фактический код довольно обширен. Можно ли показать его части? Пока спасибо.
Вам нужно только показать код, имеющий отношение к проблеме. Вы можете прочитать Как создать минимальный, полный и проверяемый пример, чтобы получить некоторую информацию о том, что вам следует добавить.
@MagnusEriksson благодарит вас за вашу помощь. Я обновил вопрос. См. Редактирование 2.
1) эээ, похоже, ни одна из ваших таблиц схемы MySQL не имеет индексов ...
@Martin Спасибо! Сделано много, чтобы добавить индекс по elev_id в одну из таблиц. Я чувствую себя NOOB. Хорошего дня!
@ Per76, пожалуйста, посмотрите мой ответ ниже.






Судя по ответу Per76, этот комментарий представляется эффективным решением:
None of your MySQL Schema tables seem to have indexes.
Итак ... добавьте индексы в свои таблицы SQL. В идеале вам следует проиндексировать все столбцы, на которые вы ссылаетесь в любом предложении WHERE, любом предложении JOIN или любом ORDER BY. Индексирование - ключ к быстродействию MySQL.
Повышение производительности запросов за счет индексации столбцов в MySQL
Как добавить индексы в таблицы MySQL?
ПРИМЕЧАНИЕ: Перечисленные здесь предложения - микрооптимизация и будут иметь лишь минимальное влияние на время загрузки страницы и / или эффективность. Это настройки Только, и их улучшения будут бледными по сравнению с улучшениями, полученными от реализации правильной индексации столбцов в MySQL, как указано выше.
Использование PHP-операторов switch вместо повторяющихся elseif.
if ($iup_info['kunsk_klick'] == "F"){$betyget = 'O';}
elseif ($iup_info['kunsk_klick'] == "E"){$betyget = '1';}
elseif ($iup_info['kunsk_klick'] == "C"){$betyget = '2';}
elseif ($iup_info['kunsk_klick'] == "A"){$betyget = '3';}
elseif (empty($iup_info['kunsk_klick'])) {$betyget = "P"; }
становится
switch($iup_info['kunsk_klick']) {
case "F":
$betyget = 'O';
break;
case "E":
$betyget = '1';
break;
case "C":
$betyget = '2';
break;
case "A":
$betyget = '3';
break;
case "":
$betyget = 'P';
break;
}
Используйте правильный MySQL Целочисленный тип для определений столбцов. Многие из ваших столбцов INT с длиной всего 3, 4 или 5 столбцов могут быть UNSIGNED SMALLINT.
INT(4) сравнивались с другими столбцами INT(4) в предложениях JOIN и WHERE.utf8mb4 вместо дрянного 3-байтового UTF-8 (Хм? Wtf?)if: (int)$arskursen===6 быстрее и эффективнее (за небольшую отметку), чем $arskursen=='6'Исправьте свой PHP, чтобы ТОЛЬКО выводил данные столбца названный, а не также данные числовых индикаторов (вы играете с вдвое большим количеством данных, чем необходимо в PHP). Пример:
Array (
[kunsk_id] => 138561
[amne_id] => 1
[radnummer] => 5
[elev_id] => 1227
[arskurs] => 5
[lid] => 1
[kunsk_klick] => E
[datum] => 2018-05-29
)
Просто из любопытства, есть ли какие-либо ссылки на «повышение эффективности» (которое вы упомянули в комментарии под OP) при использовании switch/case вместо if/else? В этом случае (без каламбура) использование switch/case действительно делает код более читаемым, но все, что я читал по этому поводу, в основном заканчивается выводом об отсутствии реальной разницы в производительности.
@MagnusEriksson switch только один раз считывает значение переменной и проверяет его на соответствие каждому дело. В руководстве указано: «В операторе switch условие оценивается только один раз, а результат сравнивается с каждым оператором case. В операторе elseif условие оценивается снова». Следовательно, переключение было бы немного более эффективным. Но я должен заявить, что все мои замечания, кроме индекса MySQL, будут лишь небольшими улучшениями. :-)
Конечно, но я серьезно сомневаюсь, что простое чтение переменной один или 50 раз вообще изменит какую-либо (заметную) разницу. Похоже на мать всех микрооптимизаций. :-) Это немного другое, если вы можете использовать функцию для каждого из них. Тогда может быть существенная разница.
@MagnusEriksson да, я могу с этим согласиться; поскольку на самом деле чтение мануальной записи на switch означает, что это только улучшение значительный сложных сравнений, а не простых сравнений. Но у меня есть привычка предпочитать switch блоку elseif''\_(;-)_/''.
Ничего плохого в этом нет. Во всяком случае, это часто делает код более читабельным. Я просто боюсь, что упоминание этого в ответе о производительности может привести к новому буйству типа «двойные кавычки против одинарных кавычек». Если не используется сложное выражение, то есть. В PHP так много вещей, которые люди все еще применяют, и рекомендуют использовать для заметных различий в некоторых ситуациях, но в основном это проблемы сегодня :-p
@MagnusEriksson Я добавил квалификатор (дис) к своему ответу выше
@Martin Спасибо! Очень любезно с вашей стороны ответить и дать действительно хорошие советы. Один (новичок) вопрос: как мне лучше всего вывести данные именованного столбца? Или, может быть: как мне не получать и данные числовых индексов?
@ Per76 используйте что-то вроде этого: php.net/manual/en/mysqli-result.fetch-assoc.php
Режим выборки по умолчанию - FETCH_BOTH. Я изменил свой режим на FETCH_ASSOC, чтобы получать только нечисловые клавиши. $ pdo-> fetchAll (PDO :: FETCH_ASSOC);
@ Per76 да, должно работать именно так, как вам нужно. :-)
Можете ли вы показать нам свой реальный код (а не только запросы)? Я предполагаю, что есть запросы в циклах? Кроме того, удостоверились ли вы, что ваши таблицы правильно проиндексированы? Уже одно это ускорит ваши запросы много.