Есть скрипт. Получает аналоги деталей, записывает их себе в базу (естественно, разные потоки могут пытаться одновременно это делать) и выводит результат. Блокирую таблицы для получения нового id и записи всей цепочки именно с ним. Если не блокировать - все отрабатывает замечательно. Если блокирую - получаю ошибку после multi_query и соответственно отсутствие вывода. Скрипт в целом использует старый способ общения с mysql и только кусок с блокировкой - mysqli. Код (PHP): <?php //создаем новое модное соединение. в рамках него же будем блокировать таблицу. $mysqli = new mysqli("server", "user", "password", "db"); ... if(empty($crossid)) { //получаем новый номер кросса, блокируя таблицу echo("get lock: ".array_pop($mysqli->query("SELECT GET_LOCK('crosses',1)")->fetch_row())."<br>"); $mysqli->query("LOCK TABLES crosses WRITE"); $crossid=intval(array_pop($mysqli->query("SELECT MAX(crossid) FROM crosses")->fetch_row()))+1; } //сохраняем запрошенный номер. если он существует, но по нему не было запросов $mysqli->query("UPDATE crosses SET req=1,added=NOW() WHERE branum='".substr(preg_replace("|[^A-Z0-9]|","",strtoupper($brands[$partnum])),0,4).$partnum."'"); //иначе это новый номер if(!$mysqli->affected_rows) $mysqli->query("INSERT INTO crosses SET branum='".substr(preg_replace("|[^A-Z0-9]|","",strtoupper($brands[$partnum])),0,4).$partnum."',brand='".$brands[$partnum]."', number='".$partnum."',crossid='".$crossid."',req=1,added=NOW()"); //сохраняем номера аналогов $repldata=""; foreach($crosses as $v) $repldata.="INSERT IGNORE INTO crosses SET branum='".substr(preg_replace("|[^A-Z0-9]|","",strtoupper($v['brand'])),0,4).$v['number']."',brand='".$v['brand']."', number='".$v['number']."',crossid='".$crossid."';"; echo("is free lock1: ".array_pop($mysqli->query("SELECT IS_FREE_LOCK('crosses')")->fetch_row())."<br>"); $mysqli->multi_query($repldata); echo("is free lock2: ".array_pop($mysqli->query("SELECT IS_FREE_LOCK('crosses')")->fetch_row())."<br>"); $mysqli->query("UNLOCK TABLES"); ... Получаю выхлоп: 204 - это где последний SELECT IS_FREE_LOCK. Почему после multi_query не срабатывает следующий mysqli()->query? Используй [code=php] чтобы было красиво. — модераторъ
наверное mysqli::$error скажет тебе больше, чем мы. Добавлено спустя 2 минуты 17 секунд: p.s. не вижу смысла в multiquery. один только гемор.
был пуст... хотя... может, я его не там писал... попробуй записать несколько десятков тысяч строк, когда скрипт находится на одном сервере, а база данных - на другом континенте.
А ты просто попробуй раздельные запросы и посмотри, сколько времени они будут выполняться. По теме: "Commands out of sync; you can't run this command now". А проблема была в том, что перед использованием fetch_row() надо почистить вывод от multi_query. Код (PHP): while($mysqli->next_result()) $mysqli->store_result(); Вот что называется "утро вечера мудренее"... Подсказка от модератора: Любой код или текст конфигурации пишите между тегом [code=php] и [/code]. Используйте отступы в коде для форматирования текста. Это помогает быстрее понять вас, увеличивает шанс на получение ответа. Что выделять? Например: PHP, HTML, CSS, JavaScript, SQL, XML, .htaccess, ini, регулярные выражения, код шаблонизаторов, любая другая разметка, результаты array/object dump и т. д.
это я и называл гемор ) выгода multi_query только во времени пересылки команд — это не самые большие затраты. отдельные команды через точку-с-запятой отстаются отдельными командами: для каждой строится новый план выполнения. т.е. сам сервер бд такую посылку быстрее отдельных команд не обработает! заметный выигрыш можно было бы получить создавая одну длинную команду вида Код (PHP): INSERT INTO xx(...) VALUES (...), (...), (...), ... или через подготовленные запросы (только не-эмулированные, а реальные серверные). и не нужен никакой multi_query! Добавлено спустя 3 минуты 2 секунды: еще я заметил, что ты используешь INSERT IGNORE. т.е. ты не уверен в безошибочности данных и никак не контролируешь результат. это допустимо в твоей задаче? Добавлено спустя 12 минут 21 секунду: вот этот момент особенно настораживает. автоинкремент и mysqli::insert_id() были бы правильным решением!!! чужой id из параллельного процесса ты никак не получишь! так что все эти напряги зря изначально.
Не пойдет. Автоинкремент идет по primary id, а crossid это дополнительный, по которому автоинкремент не сделаешь. А слежение, не превысила ли длина команды допустимую - не гемор? Не скажи. Разница в моем случае - в десятки раз.
хозяин барин. ты продолжаешь заблуждаться. в mysql нет ограничения на длину запроса. есть лимит размера посылки. и ты со своим множеством insert-ов с альтернативным синтаксисом исчерпаешь его ещё быстрее. алсо, не зная структуры не могу утверждать, но предполагаю, что можно было выбрать правильный primary key. сейчас у тебя два уникальных ключа, это уже нарушение нормальной формы. насколько оправданно, хз. ты конечно скажешь, что так надо и конец ))) ты сравнивал время выполнения множества insert (через multi_query) с одним длинным insert? не думаю. Добавлено спустя 9 минут 25 секунд: смеху ради сравнил два варианта вставки 10 строк: Код (PHP): INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; INSERT INTO table SET fil1="234", fil2="324"; и Код (PHP): INSERT INTO table(fil1, fil2) VALUES ("234", "324"), ("234", "324"), ("234", "324"), ("234", "324"), ("234", "324"), ("234", "324"), ("234", "324"), ("234", "324"), ("234", "324"), ("234", "324"); Длины: 470 против 197 ))) Ну про скорость уже всё сказано до нас: http://dev.mysql.com/doc/refman/5.7/en/insert-speed.html Так что, как минимум, рассмотри альтернативы.