我卡在这里。从.sql文件中顺序调用存储过程
我有一个过程,我想连续运行X *次。 (* X是几千倍)
基于输入数据的过程是这样做的:
1.查找actions.id,如果找不到LEAVE
s。
2.查找users.id,如果找不到,则创建一个并使用LAST_INSERT_ID()
; 3-5。寻找summaries.id(3种类型,总计,每日和每月),如果没有找到,创建一个并使用它的ID。
6.收集完所有必需的id后,将INSERT
的新行记录到操作中,并更新事务中的汇总行,如果有任何操作失败 - 则执行ROLLBACK
- 不会造成任何损害。
7.取决于结果SELECT
的消息。
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行,它找到了两个汇总ID(第3步)。
我认为这可能是由于早些时候(第375-376行)存在针对同一个用户的同一用户的调用。
就好像mysql没有及时更新表格一样,因此当行376被执行时,从行375创建的CALL
中的汇总行不可见 - 因此会创建另一个汇总行。
我试过延迟电话...
B.使用mysql的SLEEP(duration)
。
这并没有改变任何东西。执行停止在同一个CALL处。
我现在没有想法。
建议和帮助非常感谢。
注意:重复操作名称和用户名称。
PS。请记住,这是我写的第一个程序之一。
PS2。运行MySQL 52年5月1日 - 社区登录64位(视窗7U),PHP 5.3.2和Apache 2.2.17
编辑
我已经删除问题的PHP相关部分的separate question here 。
EDIT2
好吧,我已经删除从.sql文件的第一个200个电话。由于某种原因,它在前一行停止执行的过程中很顺利。现在它停在1618行。
这意味着,在某一时刻,一个新近的INSERTed
汇总行暂时不可见,因此当它发生下列其中一个迭代想要SELECT
时,它仍然无法访问。这是一个MySQL的错误?
EDIT3
现在有我注意到另一个有趣的事情。我调查了两个users_summaries创建的位置。发生这种情况(并非总是,但如果是,则是)当两个CALL指向相近的相同user
和action
时。它们可以彼此相邻,也可以由1或2个不同的呼叫分开。
如果我将其中一个(在.sql文件中)移动到低于50-100行(较早执行),那就好了。我甚至设法使.sql文件作为一个整体工作。但是这仍然不能真正解决问题。 3000行没有那么糟糕,但如果我有100000,我就会迷路。我不能依靠手动调整.sql文件。
@Michal M - 尝试改变“SELECT”错误';“到更详细的,如“选择”错误 - RETREIVING action.id';“,这样更容易识别哪个部分有错误 – ajreal 2010-11-26 10:04:19
如果我们谈论前两种方法(A,B),比我知道的究竟哪一部分是。事实上,`SELECT'错误'`根本不会发生。在第3步我得到2行,这意味着早期的`SELECT users_summary.id`确实返回NULL而不是数字,导致第二行被插入。 – 2010-11-26 10:19:37