在大型表上的SP调用期间遇到错误2013

时间:2016-05-08 00:15:14

标签: mysql stored-procedures indexing

我在SP呼叫期间遇到丢失的连接错误,从“有效的”和“有效”之间分割出日期。表A中的“有效到”列,并将它们与其他列一起插入到新表B中。

表A有大约300万行,所以我预计表B可能超过1000万行。

SP运行600秒,然后显示2013错误。

我尝试过多次调用此SP,但没有成功。

我该如何解决这个问题? 分区表A会以任何方式帮助吗?

索引怎么样?

表A如下:

     CREATE TABLE `test_data`.`offer_master` (
      `off_id` INT NOT NULL primary key,
      `hot_id` INT NOT NULL,
      `curr_id` INT NOT NULL,
      `price_dollar` FLOAT NULL DEFAULT NULL,
      `price_local` FLOAT NOT NULL,
      `curr_code` VARCHAR(35) NOT NULL,
      `valid_from` DATETIME NOT NULL,
      `valid_to` DATETIME NOT NULL,
      `breakfast_included` TINYINT(1) NOT NULL,
      `valid_offer` TINYINT(1) NOT NULL)
       ENGINE=InnoDB DEFAULT CHARSET=utf8;

表B:

     CREATE TABLE `test_data`.`split_by_date` (
    `id` int NOT NULL, 
    `hotel_id` int not NULL,
    `original_price` float not NULL,
    `currency_id` int not NULL,
    `dates` date DEFAULT NULL)
    ENGINE=InnoDB DEFAULT CHARSET=utf8;

SP将A&的日期分开插入B:

delimiter //

CREATE PROCEDURE `split_dates`()
BEGIN
DECLARE aid INT;
DECLARE avalid_from_date DATE;
DECLARE avalid_to_date DATE;
DECLARE sp_hotel_id INT;
DECLARE local_price float;
DECLARE sp_currency_id int;
DECLARE tempdt DATE;
DECLARE done INT DEFAULT FALSE;
DECLARE getdates CURSOR FOR 
SELECT off_id,valid_from,valid_to,hot_id,price_local,curr_id 
from offer_master;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

OPEN getdates;

read_loop: LOOP
FETCH getdates 
INTO aid,avalid_from_date,avalid_to_date,sp_hotel_id,local_price,sp_currency_id;

    IF done THEN
  LEAVE read_loop;  
END IF;

set tempdt=date(avalid_from_date);

WHILE (tempdt <= date(avalid_to_date)) do
  insert into split_by_date(id,hotel_id,original_price,currency_id,dates) 
  values(aid,sp_hotel_id,local_price,sp_currency_id,tempdt);
  set tempdt=tempdt+INTERVAL 1 DAY;
end while;


 END LOOP;
 CLOSE getdates;
 END
 //

1 个答案:

答案 0 :(得分:0)

快速修复可能是

START TRANSACTION;
CALL ... ;
COMMIT;

更好的解决方法是认识到CURSORs几乎总是写SQL的错误方法。我们可以通过同时处理所有300万行来摆脱光标。但我不知道如何摆脱WHILE循环。

SELECT @n := 0;  -- Or "1"?  (depends on whether you want to start with `valid_from`.
myloop:  LOOP
    INSERT INTO split_by_date(id, hotel_id, original_price, currency_id, dates)
        SELECT            off_id, hot_id,   price_local,    curr_id,
                          valid_from + INTERVAL n DAY
            FROM offer_master
            WHERE valid_from + INTERVAL @n DAY < valid_to;  -- maybe "<=" ?
    IF ROW_COUNT = 0 THEN
        LEAVE myloop;    -- when a pass over the data has no rows to add
    END IF
END LOOP myloop;

INDEXPARTITION会有所帮助;它只需要反复进行表扫描。

但是,每张桌子上至少应该有一个PRIMARY KEY

使用FLOAT钱是不明智的。请参阅DECIMAL