Здравствуйте, столкнулся вот с какой проблемой при работе с PHP7. Из-за большого кол-ва подключений к БД упал сервер - хотя это было всего треть из необходимого. Мне нужно было из csv файла залить в БД данные с админки. Разбор csv файла на строки для таблицы я сделал но когда стал прогонять запись в БД сервер упал. Причем упал вот из-за этого кода: Код (Text): function metki_insert ($profesia,$metki) { $link_db=con_db(); // коннект с БД $q_m = "SELECT `id`, `metki` FROM `professia` WHERE `name`='".$profesia."' OR `nami`='".$profesia."'"; //print $q_m; // берем id из БД для того чтобы знать куда записывать $result_m=mysqli_query($link_db,$q_m); // выполняем запрос $res_m = mysqli_fetch_all($result_m, MYSQLI_ASSOC); // получаем массив $ro_m=count($res_m); // кол-во данных в массиве if ($ro_m!=0){ // если не пустой $id_pm = $res_m[0]['id']; // id $pm = $res_m[0]['metki']; // записанная метка в поле $s1=explode(", ", $metki); $s2=explode(", ", $pm); // преобразуем строки в массив $rs1=array_diff($s1,$s2); // сравниваем два массива if (count($rs1)!=0) { // если есть отличие $srs=implode(",", $rs1); // преобразуем в строку if ($pm!=="") { $pm=$pm.' ,'.$srs; } if ($pm!==="") { $pm=$srs; } // добавляем к уже имеющимя меткам новые метки. Не всегда корректо работае else поэтому через if $qz="UPDATE `professia` SET `metki`='".$pm."' WHERE `id`='".$id_pm."' LIMIT 1"; // запрос на обновление записи mysqli_query($link_db,$qz); // выполнить запрос } } if ($ro_m==0){ // не нашлась запись $q_mz ="INSERT INTO `professia` ( `id` , `name` , `nami` , `metki`) VALUES ('', '$profesia', '', '$metki')"; // запрос на создание записи mysqli_query($link_db,$q_mz); // выполнить запрос } mysqli_close($link_db); // закрыть соединение }; Перед тем как выполнить данную функцию я проверяю а переданны ли метки если да то выполнить функцию: Код (Text): $metki=trim($metki); // убираем лишние пробелы $metki=str_replace(' ',' ',$metki); // проверяю на двойные пробелы внутри записи if ($metki!='' && $metki!=' ') { metki_insert ($profesia,$metki); } // если значение не пустое и не пробел то выполнить функцию. В итоге я проверял тестовый файл с кол-вом записей равное 490 строк. Внутри файла 19 столбцов из них 7 столбцов получают id c таблиц БД для того чтоб не дублировались значения и места меньше занимали. Может чтоб уменьшить кол-во обращение к БД сделать потоковую обработку запросов на запись. Скажем создать листинг запросов (массив sql-запросов). Я так понимаю это вложенные запросы друг в дружку сделать тогда запросов а точнее конектов к БД можно уменьшить. В 4 версии все было намного проще один раз подключился выполнил что хотел и отключил БД а тут (в PHP7) постоянный коннект с каждым запросом получается.
зачем?? сделайте сингтон и в рамках жизни скрипта пользуйтесь одним подключением к БД.... 490 строк не много.. 490 подключений может быть и не мало))
Алекс8 а подскажи пожалуйста как - выложи любой пример. У меня же из-за вот этой команды Код (Text): mysqli_query($link_db,$q_m); такое большое кол-во подключений получается
не.. у Вас не изза этой команду.. тут Вы просто запрос отправляете на сервер.. соединение у Вас вот тут инициируется $link_db=con_db(); // коннект с БД если функция function metki_insert запускается многократно и потом не закрывается соединение то вполне может быть что вот тут и получается много соединений с БД.. каждый раз новое, в то время когда старое еще висит.. выложите тут листинг функции con_db .. посмотрим)
Алекс8 соединение с БД у меня в начале функции и в конце функции стоит mysqli_close($link_db); Но сервер остановился при вызове данной функции. Когда позвонил в техподдержку хостинга мне сказали что у меня много запросов к БД.
если у Вас эта функция где то вызывается в цикле, тогда надо продумать как объединять много запросов в один.. к примеру инсертить одной строкой... только эта функция мало о чем говорит..
Ну я в начале темы это и написал. Что может пытаться создать массив на запросы а выполнить его потом методом склейки JOIN или можно попытаться написать вида SELECT; SELECT; SELECT;...- что посоветуете. А данная функция вызывается в цикле при прохождение по полученным данным из файла. Причем я ее вызов тоже вверху прописал в итоге там вызовов этой функции так как не во всех столбцах есть значение около 100 наберется. --- Добавлено --- Я нашел что в mysql можно использовать функции IN() хотя возникает вопрос а сколько запросов можно отправить сразу. Как узнать максимальное кол-во запросов за один раз?
MouseZver я у вас совета и прошу как лучше это сделать чтоб получился запрос в БД вида SELECT; SELECT; SELECT;... Просто почитал заодно что есть в интернете. Но естественно у меня возникает вопрос а какое кол-во я таких запросов могу отправить сразу. Как это узнать - чтоб опять сервер не упал. Или может вообще GROUP BY использовать. Понимаю что в таком случае надо будет использовать AS для присвоения результата из БД к тем 7 параметрам что берут значение из БД и для запроса вида UPDATE. В общем есть с чем эксперементировать но хотелось бы обезопасить себя объемом отправленных данных или кол-вом за один раз на обработку. Мне ведь еще надо будет отправлять запросы INSERT и UPDATE. А искал я в гугле по запросу вложенные запросы в mysql.
1. Проблема не в php7 и вообще не в php - а в жутком коде 2. Было бы гораздо правильнее и логичнее вынести все метки в отдельную таблицу, а так же создать кросс таблицу для соответствия меток и профессий. Тогда весь процесс добавления меток уместился бы один SQL запрос типа INSERT INTO ..... ON IGNORE 3. правильно сказали - ненужно 100500 раз открывать и закрывать соединение БД, в начале скрипта открыли - в конце закрыли - все...
подожди --- Добавлено --- @victort выпиши сюда sql строки ПОЛНЫЕ --- Добавлено --- а не SELECT; SELECT; SELECT;...
ADSoft метки и профессии итак вынесены в отдельную таблицу. Каждая метка относится к конкретной профессии. Поэтому и идет запрос в БД с передачей профессии после чего происходит проверка а есть ли такая метка у профессии если какой-то метки нет то создается новый список меток с добавлением в него несуществующих в нем меток. После чего новый список меток добавляется в таблицу. MouseZver - задача такая дается csv файл с 19 столбцами которые записываются в таблицу vakansii. Перед тем как сделать записать идет запрос в БД по профессиям если есть профессия то берется ее id если нету то создается запись в таблицу профессия с новой профессией. После чего идет запрос в БД чтоб взять id. Так как есть вероятность что в какой-то момент может так получиться что id не будет следующим за последним. А именно может оказаться что в профессию вкралась ошибка и чтоб небыло дублежа ее удалили руками отдав ее вакансии в правильную строку с профессией. Вот код проверки: Код (Text): $pro=proverit ($profesia, "professia"); - первый параметр в функции переменная второй имя таблицы. Вот сама функция: Код (Text): function proverit ($pr, $tab){ $link_db=con_db(); $q_pro = "SELECT * FROM `".$tab."` WHERE `name`='".$pr."'"; if ($tab=="professia") {$q_pro.=" OR `nami`='".$pr."'";} $res_pro = mysqli_query($link_db,$q_pro); $res_pro_pl = mysqli_fetch_all($res_pro, MYSQLI_ASSOC); $ro=count($res_pro_pl); $id=0; if ($ro>0) { $id=$res_pro_pl[0]['id']; //$id = mysql_result($res, 0, 'id'); if ($tab=="new_professia") { $nm=$res_pro_pl[0]['nami']; //$nm = mysql_result($res, 0, 'nami'); if ($pr=="$nm") { $id=$id+0.1; } } } mysqli_close($link_db); return $id; }; из данной функции видно что у профессии есть дополнительное поле nami оно отвечает за написание профессии во множественном числе. Если значение равно во множественном числе то возвращается id с плавающей точкой чтоб показать при отображение записи из основной таблицы что надо брать значение из второго поля. По такому же принципу проверяется поле рубрики куда попадает вакансия Код (Text): $rub=proverit ($rubrika, "rubriki"); и столбец параметры Код (Text): $par=proverit ($parametri, "parametri"); если значения в данных столбцах отличаются от записи в файле а это означает что id=0 то в этом случае идет запрос в эти таблицы по получению списка и выдачи на экран чтобы пользователь выбрал из уже имеющего списка правильное значение это осуществляется функцией Код (Text): select_vibor("rubriki",$n); Вот сама функция: Код (Text): function select_vibor ($tab,$i){ $link_db=con_db(); $q_vib = "SELECT * FROM `".$tab."` ORDER BY `name` ASC"; $res_vib = mysqli_query($link_db,$q_vib); //$res = mysql_query($q); $res_vib_pl = mysqli_fetch_all($res_vib, MYSQLI_ASSOC); $ro_vib=count ($res_vib_pl); //$ro_vib=mysql_num_rows($res_vib_pl); $spp='<select size="1" name="'.$tab.'['.$i.']">'; for($n=0; $n<$ro_vib; $n++){ $id=$res_vib_pl[$n]['id']; //$id = mysql_result($res, $n, 'id'); $nam=$res_vib_pl[$n]['name']; //$nam = mysql_result($res, $n, 'name'); if ($tab=='professia') { $nami=$res_vib_pl[$n]['nami']; /*$nami = mysql_result($res, $n, 'nami');*/ } $spp.='<option value="'.$id.'">'.$nam.'</option>'; if ($tab=='professia' && $nami!='') { $spp.='<option value="'.$id.'">'.$nami.'</option>'; } } $spp.='</select>'; mysqli_close($link_db); return conv ($spp); }; Ну кстати этот же список предоставляется и при проходе через переменную профессия. Но я добавляю чекбокс чтоб пользователь мог указать что профессия новая а значит ее надо добавить в таблицу профессий. Остальные переменные проходят через разные команды не связанные с обращением к БД на проверку записей (такие как trim) Это первая стадия обработки файла на экран пользователя выйдут сообщения об неточностях в конкретных строках. После того как пользователь указал все что необходимо он нажимает на кнопку продолжить загрузку. В первой строке происходит запись новых профессий и получение их id: Код (Text): $_POST[new_professia][$i]=insert_danie_prof($_POST[new_professiaN][$i] Вот сама функция: Код (Text): function insert_danie_prof ($dan){ $link_db=con_db(); $dan = htmlspecialchars($dan, ENT_QUOTES); $q = "SELECT * FROM `professia` WHERE `name`='".$dan."' OR `nami`='".$dan."'"; //print $q; $result_p=mysqli_query($link_db,$q) ?? ''; $ro=mysqli_num_rows($result_p); if ($ro==0){ $q_z ="INSERT INTO `new_professia` ( `id` , `name` , `nami` , `metki`) VALUES ('', '$dan', '', '')"; $q_p = "SELECT * FROM `new_professia` WHERE `name`='".$dan."' OR `nami`='".$dan."'"; //print $q_p; $result_p=mysqli_query($link_db,$q_z); $result_pp=mysqli_query($link_db,$q_p); $res_pp = mysqli_fetch_all($result_pp, MYSQLI_ASSOC); $ro_pp=count($res); for ($i=0; $i<$ro_pp; $i++) { $id = $res_pp[$i]['id']; } };//if mysqli_close($link_db); return $id; }; Ну и происходит сама запись всех столбцов в таблицу: Код (Text): $q="INSERT INTO `vakansii_2017` ( `id` , `id_rub` , `id_prof` , `id_pred` , `id_param`, `graf_rab` , `op_rab`, `zp`, `zp_c`, `treb`, `usl`, `id_raion`, `id_obrz`, `inf`, `adr`, `tel`, `e-mail`, `sait`, `socseti`, `flag`, `data_p`, `time_p`, `flag_v`, `data_okn_v`, `time_okn_v`, `data_okn_p`, `time_okn_p`, `count`, `tek_count`) VALUES ('', '".$_POST[new_rubriki][$i]."', '".$_POST[new_professia][$i]."', '".$_POST[predpriatie][$i]."', '".$_POST[new_parametr][$i]."', '".$_POST[grafik][$i]."', '".$_POST[opit][$i]."', '".$_POST[zp][$i]."', '".$_POST[zpc][$i]."', '".$_POST[treb][$i]."','".$_POST[usl][$i]."','".$_POST[raion][$i]."','".$_POST[obraz][$i]."','".$_POST[inf][$i]."','".$_POST[adr][$i]."','".$_POST[tel][$i]."','".$_POST[email][$i]."','".$_POST[sait][$i]."','".$_POST[socseti][$i]."', '2', '".$a_dat[0]."', '".$a_dat[1]."', '', '', '', '', '', '', '')"; print $q; print '</br>'; //$p=mysqli_query($link_db,$q) ? $z1 : $z2; // записываем в БД Как видно из кода отправка в БД запроса закоментирована - просто перед тем как ее раскоментировать я хотел убедиться что все строки созданы и можно отправлять на запись но до этого не дошло сервер упал. Ну и тот кто посмотрит файл увидит вверху файла проверку пользователя. Может я и перемудрил с код . Но надеюсь я смог понятно описать что я пытался сделать и для чего это нужно. Кстати в файле закоментированы команды mysql все по той же причине что я перебираюсь с 4 версии в 7. И как только все отлажу тогда можно будет и удалять. Так что извините за мусор. И еще я как говориться не успел но было такое пожелание чтоб перед записью я проверял а есть ли такое объявление в БД если есть то не записывать. В файле вы увидете функцию которая удаляет все вакансии из таблицы. Так вот я думал сделать функцию которая будет проверять если есть идентичная запись то менять у нее флаг 2 ну скажем на 7 из массива на запись данную строчку удалять а потом запустить функцию очищения таблицы и сделать запись после чего все флаги с 7 опять поменять на 2.
Блин меня осенило или я не прав. Можно ведь сделать одно подключение вначале файла и потом этот параметр передавать в функцию как переменную а закрыть коннект в конце файла. Тогда будет одно подключение к БД.
это одна из проблем была решена, теперь нужно оптимизировать запросы. > записываем новые профессии, не создавая дубликаты Код (Text): INSERT IGNORE INTO `prof_table` ( `column1`, `column2` ) VALUES ( 'инженер', 555 ), ( 'водитель', 555 ), ( 'механик', 555 ), ( 'армировщик', 555 ), ( 'электрик', 555 ) PHP: <?php # php version 7.2 error_reporting ( E_ALL ); # из csv данные $arr = [ [ 'инженер', 555 ], [ 'водитель', 555 ], [ 'механик', 555 ], [ 'армировщик', 555 ], [ 'электрик', 555 ], ]; $new = []; foreach ( $arr AS $item ) { $new[] = sprintf ( '( \'%s\', %d )', ...$item ); } unset ( $arr, $item ); echo sprintf ( 'INSERT IGNORE INTO `prof_table` ( `column1`, `column2` ) VALUES %s', implode ( ', ', $new ) );
MouseZver перед тем как использовать твой код решил потестить его через phpMyAdmin Код (Text): INSERT IGNORE INTO `professia` ( `name`, `nami`, `metki` ) VALUES ( 'Инженер', 'Инженеры' ,'' ) Данная запись в таблице есть но он всеравно ее добавил в конец таблицы. Разъясни пожалуйста где ошибка.
поле профессии должно быть уникальным --- Добавлено --- ALTER TABLE `test`.`table` ADD UNIQUE `r` (`r`);
MouseZver данный метод не подойдет из за того что в данный массив попадают вот какие значения: Код (Text): $arr = [ [ 'инженер', 555 ], [ 'инженеры', 555 ], [ 'водитель', 555 ], [ 'механик', 555 ], [ 'механики', 555 ], [ 'армировщик', 555 ], [ 'электрик', 555 ], ]; то есть не только в единственном числе но и во множественном. Извини что сразу не написал об этом. Поэтому я и использую запрос SELECT * FROM `professia` WHERE `name`='".$dan."' OR `nami`='".$dan."'"; Да в таком подходе есть минус что множественное значение запишется в поле предназначенное для единственного числа. Но это можно исправить. Указав при загрузке а точнее при прохождении проверки на ошибки чтоб это значение было записано во второе поле а в первое поле вписать как будет в единственном числе.
То что не правильно я пользовался подключением к БД. А дойдя до этого кода просто ресурсы у сервера иссякли. Теперь я это исправил. В таблице есть индексное поле 'id' называется, а поле 'name' еще и как уникальное прописано. Мне MouseZver предложил как оптимизировать запись но к сожалению в моем случае без первичного запроса это сделать не получиться. Надо вначале узнать есть ли такое значение в поле 'name' или 'nami' из поданного массива а потом уже делать запись если нету или взять 'id' раз есть.