Помогите пожалуйста есть запрос который очень медленно выполняется и нужно его упростить вот он [sql] UPDATE `userlist` SET `status` = 'tested', `limit` = '0' WHERE `status` = 'works' AND (SELECT COUNT(*) FROM `visitors` WHERE `where` = `userlist`.`url` AND DATE(datetime) = ADDDATE(DATE(NOW()),-1) LIMIT 0 , 3) < 3; [/sql] я попробовал его упростить но запускать упрощенный вариант боюсь правильно ли я сделал? [sql] UPDATE `userlist` AS `u` LEFT JOIN ( SELECT `where`, COUNT(*) AS `count` FROM `visitors` WHERE DATE(`datetime`) = ADDDATE(DATE(NOW()), -1) GROUP BY `where` ORDER BY NULL ) AS `v` ON `u`.`url` = `v`.`where` SET `u`.`status` = 'tested', `u`.`limit` = '0' WHERE `u`.`status` = 'works' AND IFNULL(`v`.`count`, 0) < 3 [/sql] или у кого какие идеи пишите
lrlr Тут оптимизировать запрос очень проблематично. Операция сравнения в предложении конъюкции заставляет обрабатывать кучу строк каждой записи, при этом каждый раз делается выборка по условию и подставляется в другой запрос, который выполняет подобную операцию. Суть в том, что САМ ЗАПРОС сложный. Не то, как ты его перепишешь, а как ты перепишеш ЛОГИКУ запроса. Для этого тебе прийдется менять не только запрос, но и обработчик со стороны скрипта.
Apple т.е. хотите сказать что майскьюрл говнецо? и умеет работать только с одной таблицей тогда какого хрена им все пользуются, в блокноте и то выборка цикл в цикле быстрее работать будет не верю, нужно как то обьеденить 2 таблицы в одну и потом по ней проехаться апдейтом
таблица визиторс 210300 записей таблица юзерлист 570 записей через месяц все удвоится в смысле движок? сам пишу задолбала эта тормазуха, месяц проходит и снова нужно придумывать велосипед
если посчитать из выше сказанного то проверяется 210300 * 570 записей типа цикл в цикле и это 119871000 строк за 40 сек ну если конечно вычесть правильно составленный запрос то в 2 раза меньше но это роли не играет
итак... второй запрос набрался смелости и проверил мозг не подвел он работает и время его выполнения 0.1 сек напомню что первый выполнялся 30-40 сек но вот на счет того правильно ли он в базе все обновил понять не могу потому что слишком большая база нужен ответ на вопрос правильно ли я составил второй запрос? прошу потратить свое время всем кто хорошо знает данную тему, потому как вопрос не детский...
Если у Вас каждый месяц таблица будет расти на несколько сотен записей, то правильно будет переделать БД, - иначе всё равно рано или поздно упрётесь в предел. А вообще, попытайте простое решение: разделить выборку и обновление записей. Выборку запихать во временную таблицу, затем по ней изменять записи. В некоторых случаях мне удавалось таким образом ускорять изменение на порядок за счёт оптимизации выборки ИД-шек. Естественно, должны быть все необходимые индексы. Т.е. что-то вроде этого: 1) Создать времнную таблицу и запихать туда Вашу выборку, как-то так: [sql]SELECT userlist.id, COUNT(*) as count FROM `visitors` inner join userlist on userlist.url = visitors.where WHERE DATE(datetime) = ADDDATE(DATE(NOW()),-1) group by userlist.id having count < 3; [/sql] 2) Затем изменить найденные записи, как-то так: [sql]UPDATE `userlist` SET `status` = 'tested', `limit` = '0' WHERE id in (select id from tmp) and `status` = 'works';[/sql]
Надеюсь, не на рабочей базе, а на тестовой Ну какие проблемы? Сделайте тест для первого варианта, затем для второго. Результаты сравните - равны, значит предположительно работает правильно.
в том то и дело что не на тестовой... теперь ничего не сравнить. нужно ждать сутки для следующей проверки
так там же UPDATE используется база такой конфигурации что если запихнуть первый запрос обратно через сутки все вернется в прежнее состояние если второй запрос напортачил она само восстанавливаемая попытался конечно сделать экспорт базы, но она как пошла качать в итоге блокнот вырос до 63 мб и перестал вообще грузится с загрузкой архивов тоже самое. это ппц
С первого полусонного взгляда вроде нормально. Но я бы малость поправил, примерно так: [sql] UPDATE `userlist` AS `u` inner JOIN ( SELECT `where`, COUNT(*) AS `count` FROM `visitors` WHERE DATE(`datetime`) = ADDDATE(DATE(NOW()), -1) GROUP BY `where` having count < 3 ) AS `v` ON `u`.`url` = `v`.`where` SET `u`.`status` = 'tested', `u`.`limit` = '0' WHERE `u`.`status` = 'works' [/sql] Это подобно тому, что я предложил выше (т.е. используется временная таблица) - разница только в том, сможет ли оптимизатор нормально обработать подзапрос. Иногда у mySQL крыша едет в таких случаях. Если не едет - такой вариант лучше, чем два отдельных запроса.
Какой блокнот, причём тут блокнот... Выгружаете дамп этих двух таблиц себе на локалку и делайте с ними что хотите - тестируйте, ломайте, изменяйте, сравнивайте... Когда уверены, что Ваш код правильный - кладёте на сервер. Это же азы, 2х2.
если в запросе который должен пройти по всей БД есть еще подзапрос, который на каждую строку делает выборку - это неправльная организация БД вцелом. Оптимизировать тут нечего. Надо вводить флаги, промежуточные таблицы и прочее. Соотв. все это совместно с правильно расставленными индексами правильных типов. =)
а что ты пытаешься сделать? Может то, что ты хочешь сделать можно сделать более простым запросом? Ну и нужно привести структуру таблиц и назначение полей
нет а вот кстати еще один аналог запроса [sql] DROP TEMPORARY TABLE IF EXISTS tmp1; CREATE TEMPORARY TABLE tmp1 AS SELECT `where`, COUNT(*) AS `count` FROM `visitors` WHERE DATE(`datetime`) = ADDDATE(DATE(NOW()), -1) GROUP BY `where`; ALTER TABLE tmp1 ADD PRIMARY KEY (`where`); UPDATE `userlist` AS `u` LEFT JOIN tmp1`v` ON `u`.`url` = `v`.`where` SET `u`.`status` = 'tested', `u`.`limit` = '0' WHERE `u`.`status` = 'works' AND IFNULL(`v`.`count`, 0) < 3 [/sql] но проверять его работоспособность не стал