我卡在這裏。從.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