За последние 24 часа нас посетили 17623 программиста и 1667 роботов. Сейчас ищут 1580 программистов ...

ПОМОГИТЕ!!! Упростить сложнейший запрос, срочно!

Тема в разделе "MySQL", создана пользователем lrlr, 16 мар 2011.

  1. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    Помогите пожалуйста
    есть запрос который очень медленно выполняется и нужно его упростить

    вот он
    [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]

    или у кого какие идеи пишите
     
  2. Apple

    Apple Активный пользователь

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    Захуячил в запрос джойн, молодец.
    Упростил проще некуда.
     
  3. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    Блин не упростить а ускорить нужно

    он выполняется 40 секунд епт
     
  4. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    lrlr
    Тогда разбей на несколько
     
  5. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    разбить не позволяет работа движка
    не на что разбивать...
     
  6. Apple

    Apple Активный пользователь

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    lrlr
    Тут оптимизировать запрос очень проблематично.
    Операция сравнения в предложении конъюкции заставляет обрабатывать кучу строк каждой записи, при этом каждый раз делается выборка по условию и подставляется в другой запрос, который выполняет подобную операцию.

    Суть в том, что САМ ЗАПРОС сложный. Не то, как ты его перепишешь, а как ты перепишеш ЛОГИКУ запроса.
    Для этого тебе прийдется менять не только запрос, но и обработчик со стороны скрипта.
     
  7. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    Apple
    т.е. хотите сказать что майскьюрл говнецо? и умеет работать только с одной таблицей
    тогда какого хрена им все пользуются, в блокноте и то выборка цикл в цикле быстрее работать будет
    не верю, нужно как то обьеденить 2 таблицы в одну и потом по ней проехаться апдейтом
     
  8. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Какой движок? Сколько записей в таблице всего? Сколько записей обновляется за те 40 сек?
     
  9. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    таблица визиторс 210300 записей
    таблица юзерлист 570 записей
    через месяц все удвоится

    в смысле движок?
    сам пишу

    задолбала эта тормазуха, месяц проходит и снова нужно придумывать велосипед
     
  10. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    если посчитать из выше сказанного то проверяется

    210300 * 570 записей
    типа цикл в цикле
    и это 119871000 строк за 40 сек

    ну если конечно вычесть правильно составленный запрос то в 2 раза меньше но это роли не играет
     
  11. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    InnoDB? MyISAM? ...?
     
  12. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
  13. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    итак...
    второй запрос набрался смелости и проверил
    мозг не подвел
    он работает и время его выполнения 0.1 сек
    напомню что первый выполнялся 30-40 сек
    но вот на счет того правильно ли он в базе все обновил понять не могу потому что слишком большая база
    нужен ответ на вопрос правильно ли я составил второй запрос?

    прошу потратить свое время всем кто хорошо знает данную тему, потому как вопрос не детский...
     
  14. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Если у Вас каждый месяц таблица будет расти на несколько сотен записей, то правильно будет переделать БД, - иначе всё равно рано или поздно упрётесь в предел.

    А вообще, попытайте простое решение: разделить выборку и обновление записей. Выборку запихать во временную таблицу, затем по ней изменять записи. В некоторых случаях мне удавалось таким образом ускорять изменение на порядок за счёт оптимизации выборки ИД-шек. Естественно, должны быть все необходимые индексы.

    Т.е. что-то вроде этого:
    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]
     
  15. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Надеюсь, не на рабочей базе, а на тестовой ;)
    Ну какие проблемы? Сделайте тест для первого варианта, затем для второго. Результаты сравните - равны, значит предположительно работает правильно.
     
  16. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    в том то и дело что не на тестовой...
    теперь ничего не сравнить. нужно ждать сутки для следующей проверки
     
  17. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Ну Вы герой! Запорите базу - хозяин выгонит, ещё и по шее даст. И будет прав...
     
  18. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    так там же UPDATE используется
    база такой конфигурации что если запихнуть первый запрос обратно через сутки все вернется в прежнее состояние если второй запрос напортачил
    она само восстанавливаемая

    попытался конечно сделать экспорт базы, но она как пошла качать в итоге блокнот вырос до 63 мб и перестал вообще грузится
    с загрузкой архивов тоже самое.
    это ппц
     
  19. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    С первого полусонного взгляда вроде нормально. Но я бы малость поправил, примерно так:
    [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 крыша едет в таких случаях. Если не едет - такой вариант лучше, чем два отдельных запроса.
     
  20. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Какой блокнот, причём тут блокнот... Выгружаете дамп этих двух таблиц себе на локалку и делайте с ними что хотите - тестируйте, ломайте, изменяйте, сравнивайте... Когда уверены, что Ваш код правильный - кладёте на сервер. Это же азы, 2х2.
     
  21. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    попробую...
     
  22. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    если в запросе который должен пройти по всей БД есть еще подзапрос, который на каждую строку делает выборку - это неправльная организация БД вцелом. Оптимизировать тут нечего. Надо вводить флаги, промежуточные таблицы и прочее. Соотв. все это совместно с правильно расставленными индексами правильных типов. =)
     
  23. runner

    runner Активный пользователь

    С нами с:
    16 апр 2010
    Сообщения:
    343
    Симпатии:
    1
    Адрес:
    Ташкент
    а что ты пытаешься сделать? Может то, что ты хочешь сделать можно сделать более простым запросом? Ну и нужно привести структуру таблиц и назначение полей
     
  24. lrlr

    lrlr Активный пользователь

    С нами с:
    16 мар 2011
    Сообщения:
    14
    Симпатии:
    0
    нет

    а вот кстати еще один аналог запроса :)

    [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]

    но проверять его работоспособность не стал