UPDATE и WHERE одной таблицы

12
D
На сайте с 28.06.2008
Offline
1101
612

UPDATE x55_cl_items SET count_do = (SELECT COUNT(id) FROM x55_do_working WHERE x55_do_working.cl_id = x55_cl_items.id)

Этот запрос выполняется долго. НЕмного подумал понял что обновление всех записей мне и не нужно, а хватит только тех что я изменял за последний месяц. Как сюда правильно добавить?

WHERE x55__cl_items.modified > LAST_DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))

Пробовал добавить тупо в конец первого запроса, но EXPLAIN показывает что выборка не уменьшается...

Dreammaker
На сайте с 20.04.2006
Offline
570
#1

Dram, этот запрос делается в скрипте через PHP или разово через Mysql (например, через PHPMyAdmin)?

Если первый случай, то здесь проблема в том, что для каждой строки из x55_cl_items подзапрос выполняется отдельно (то есть, условно count(id) будет подсчитываться 1000-и раз, а это уже сам по себе не медленный запрос). Поэтому его лучше выполнить отдельно, а затем уже делать запрос на обновление полей присвоив полученной значение.

Ну и лучше использовать count(*) вместо count(id) - с таким запросом база будет работать быстрее.

индекс по x55_do_working.cl_id

и примари индекс по x55_cl_items.id

Если случай второй - то набросайте php-скрипт, который запускайте, чтобы сделать выше описанное :)

A
На сайте с 19.07.2010
Offline
130
#2

у вас две таблицы :)

Dram:
UPDATE x55_cl_items

SET count_do = (SELECT COUNT(id) FROM x55_do_working WHERE x55_do_working.cl_id = x55_cl_items.id)
Этот запрос выполняется долго.

логично, что долго. для каждой строки из таблицы "item" выполняется запрос по табличке "working".

если у вас в "item" 1000 строк, то реально будет выполнено 1000+1 = 1001 sql запрос. упс, выше уже написали тоже самое, только сейчас прочитал :)

переписал ваш запрос, реально это будет два запроса, отработает моментально. нужен индекс по полю x55_do_working.id

update `x55_cl_items` t1, (SELECT id, count(*) cnt FROM `x55_do_working` group by id) t2

set t1.count_do = t2.cnt
where t1.id=t2.id
.............
D
На сайте с 28.06.2008
Offline
1101
#3
Dreammaker:
Ну и лучше использовать count(*) вместо count(id) - с таким запросом база будет работать быстрее.

c count(id) - 0.9 сек

с count(*) - 1,03 сек

---------- Добавлено 21.09.2017 в 10:14 ----------

Я тут понял как ускорить запрос - не нужно апать всю таблицу x55_cl_items

Нужно апать только те x55_cl_items.id которые равны x55_do_working.cl_id

т.е. как-то так (жирным добавил

UPDATE x55_cl_items SET count_do = (SELECT COUNT(id) FROM x55_do_working WHERE x55_do_working.cl_id = x55_cl_items.id) WHERE x55_cl_items.id = x55_do_working.cl_id



---------- Добавлено 21.09.2017 в 10:19 ----------

admak:
переписал ваш запрос, реально это будет два запроса, отработает моментально. нужен индекс по полю x55_do_working.id
Ваш запрос отработал не правильно (не правильно обновил count_do она везде стала 1) + по эксплейн обратобал в 300 раз больше строк и по времени был так же 1.09 сек. Указанные вами индекс был и раньше.
D
На сайте с 28.06.2008
Offline
1101
#4

Пока у меня в голове родилась такая каша :))

Получаем список ID фирм в которых есть работники

1. SELECT `cl_id` FROM `x55_do_working` GROUP BY `cl_id` HAVING COUNT(*)=1

Делаем подсчет сколько работников в каждой фирме

2. SELECT COUNT(id) FROM `x55_do_working` WHERE `cl_id` = каждая из записей запроса №1

Апаем только те клиники где есть работники, а не все

3. UPDATE x55_cl_items SET count_do = ЗАПРОС №2 WHERE `id` = ЗАПРОС №1

Как все это собрать в 1 запрос?

Dreammaker
На сайте с 20.04.2006
Offline
570
#5

Dram, задача стала немного яснее, но не до конца. :)

Вам нужно в таблицу раз в месяц заносить количество работников для каждой компании? Почему для компании не сделать счётчик, который обновляется по факту добавления/удаления работника? Это обычный вариант для того, чтобы не юзать ресурсоемкий count.

D
На сайте с 28.06.2008
Offline
1101
#6

count_do это и есть счетчик сотрудников в таблице x55_cl_items - он обновляется по крону раз в 10 минут (да там часто все меняется). Но запрос тяжеловат, я хочу попытаться сделать его побыстрее.

Додумался до того что не нужно апать всю таблицу x55_cl_items нужно апнуть только фирмы где есть сотрудники.

C
На сайте с 04.02.2005
Offline
277
#7

UPDATE `x55_cl_items` c
JOIN (SELECT COUNT(id) total, cl_id FROM x55_do_working GROUP BY cl_id) ct
SET
`count_do`= ct.total
WHERE c.id = ct.cl_id
D
На сайте с 28.06.2008
Offline
1101
#8

Chukcha, спасибо - 0,6 сек. Почти в 2 раза быстрее - это предел?

C
На сайте с 04.02.2005
Offline
277
#9

Если вы уменьшите вторую выборку по времени, то возможно, будет еще быстрее, количество записей второй таблицы уменьшится.

D
На сайте с 28.06.2008
Offline
1101
#10

Вот эксплейн вашего запроса

png 166809.png
12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий