Я застрял здесь.
У меня есть процедура, которую я хочу запустить X * раз подряд.(* X пару тысяч раз)
Процедура, основанная на входных данных, делает следующее:
1. Ищет action.id, если не найден LEAVE
s.
2. Ищет пользователей.id, если не найден, создает его и использует LAST_INSERT_ID()
;
3-5.Ищет резюмируемый итог (3 типа, суммарный, дневной и ежемесячный), если он не найден, создает его и использует его идентификатор.
6. После сбора всех необходимых идентификаторов INSERT
открывает новую строку в действиях и обновляетстроки суммирования в транзакции, поэтому, если какой-либо из них завершится неудачей - он ROLLBACK
- не причинит вреда.
7. В зависимости от результата SELECT
s сообщения.
CREATE PROCEDURE NEW_ACTION(
IN a_date TIMESTAMP,
IN u_name VARCHAR(255),
IN a_name VARCHAR(255),
IN a_chars INT,
IN url VARCHAR(255),
IN ip VARCHAR(15))
lbl_proc: BEGIN
DECLARE a_id, u_id, us_id, usd_id, usm_id, a_day, a_month, error INT;
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET error = 1;
SET error = 0;
SET a_day = DATE_FORMAT(SUBSTRING(a_date ,1,10), '%Y%m%d');
SET a_month = SUBSTRING(a_day, 1, 6);
/* 1. RETREIVING action.id */
SET a_id = (SELECT `id` FROM `actions` WHERE `name` = a_name);
IF a_id IS NULL THEN
SELECT 'error';
LEAVE lbl_proc;
END IF;
/* 2. RETREIVING users.id */
SET u_id = (SELECT `id` FROM `users` WHERE `name` = u_name);
IF u_id IS NULL THEN
INSERT INTO `users` (name) VALUES (u_name);
SET u_id = (SELECT LAST_INSERT_ID());
END IF;
/* 3. RETREIVING user_summaries.id */
SET us_id = (SELECT `id` FROM `users_summaries` WHERE `user_id` = u_id AND `action_id` = a_id);
IF us_id IS NULL THEN
INSERT INTO `users_summaries` (user_id, action_id) VALUES (u_id, a_id);
SET us_id = (SELECT LAST_INSERT_ID());
END IF;
/* 4. RETREIVING user_summaries_days.id */
SET usd_id = (SELECT `id` FROM `users_summaries_days` WHERE `day` = a_day AND `user_id` = u_id AND `action_id` = a_id);
IF usd_id IS NULL THEN
INSERT INTO `users_summaries_days` (day, user_id, action_id) VALUES (a_day, u_id, a_id);
SET usd_id = (SELECT LAST_INSERT_ID());
END IF;
/* 5. RETREIVING user_summaries_months.id */
SET usm_id = (SELECT `id` FROM `users_summaries_months` WHERE `month` = a_month AND `user_id` = u_id AND `action_id` = a_id);
IF usm_id IS NULL THEN
INSERT INTO `users_summaries_months` (month, user_id, action_id) VALUES (a_month, u_id, a_id);
SET usm_id = (SELECT LAST_INSERT_ID());
END IF;
/* 6. SAVING action AND UPDATING summaries */
SET autocommit = 0;
START TRANSACTION;
INSERT INTO `users_actions` (`date`, `user_id`, `action_id`, `chars`, `url`, `ip`) VALUES (a_date, u_id, a_id, a_chars, url, ip);
UPDATE `users_summaries` SET qty = qty + 1, chars = chars + a_chars WHERE id = us_id;
UPDATE `users_summaries_days` SET qty = qty + 1, chars = chars + a_chars WHERE id = usd_id;
UPDATE `users_summaries_months` SET qty = qty + 1, chars = chars + a_chars WHERE id = usm_id;
IF error = 1 THEN
SELECT 'error';
ROLLBACK;
LEAVE lbl_proc;
ELSE
SELECT 'success';
COMMIT;
END IF;
END;
Теперь яУ меня есть необработанные данные, которые я хочу передать в эту процедуру.Там в настоящее время около 3000 строк.
Я испробовал все известные мне решения:
A.# mysql -uuser -ppass DB < calls.sql
- Используя php, я в основном создал список вызовов, таких как:
CALL NEW_ACTION('2010-11-01 13:23:00', 'username1', 'actionname1', '100', 'http://example.com/', '0.0.0.0');
CALL NEW_ACTION('2010-11-01 13:23:00', 'username2', 'actionname1', '100', 'http://example.com/', '0.0.0.0');
CALL NEW_ACTION('2010-11-01 13:23:00', 'username1', 'actionname2', '100', 'http://example.com/', '0.0.0.0');
...
Этот сбой всегда (пробовал несколько раз) в строке 452, где он нашел два итоговых идентификатора (шаг 3).
Я подумал, что это может быть связано с тем, что ранее (строки 375-376) были вызовы для одного и того же пользователя для одного и того же действия.
Как будто mysql не обновлял таблицы вовремя, поэтому итоговая строка созданав CALL
из строки 375 еще не видно, когда выполняется строка 376. Поэтому создается еще одна итоговая строка.
Я пытался отложить вызовы ...
B.Использование mysql SLEEP(duration)
.
Это ничего не изменило.Исполнение снова останавливается на том же CALL.
У меня сейчас нет идей.
Предложения и помощь очень ценятся.
NOTE : имена действий и имена пользователей повторяются.
PS.Имейте в виду, что это одна из моих первых процедур, написанных когда-либо.
PS2.Запуск mysql 5.1.52-community-log 64bit (Windows 7U), PHP 5.3.2 и Apache 2.2.17
EDIT
Я удалилPHP, связанный с частью вопроса, с отдельным вопросом здесь .
EDIT2
Хорошо, я удалил первые 200 вызовов изфайл .sql.По какой-то причине все прошло хорошо после предыдущей строки, которая прекращала выполнение.Теперь он остановился на строке 1618.
Это означало бы, что в какой-то момент вновь итоговая строка INSERTed
на мгновение не видна, поэтому, когда случается, что одна из следующих итераций хочет SELECT
, этопока не доступен для них.Это ошибка MySQL?
EDIT3
Теперь я заметил еще одну интересную вещь.Я исследовал, где создаются два users_summaries.Это происходит (не всегда, но если, тогда так и есть), когда есть два ВЫЗОВА, ссылающиеся на одинаковые user
и action
в непосредственной близости.Они могут быть рядом друг с другом или разделены 1 или 2 различными вызовами.
Если я переместу один из них (в пределах файла .sql), например, на 50-100 строк ниже (выполняется раньше), чем это нормально.Мне даже удалось заставить файл .sql работать в целом.Но это все еще не решает проблему.С 3000 рядами это не так уж плохо, но если бы у меня было 100000, я потерялся.Я не могу полагаться на ручные настройки в файле .sql.