【问题标题】:MySql Batching Stored Procedure Calls with .Net / Connector?MySql 使用 .Net / 连接器批量存储过程调用?
【发布时间】:2011-06-07 13:33:48
【问题描述】:

有没有办法在 MySql 中使用 .Net / Connector 批量存储过程调用以提高性能?

这是场景...我正在使用一个接受一些参数作为输入的存储过程。此过程基本上检查是否应该更新现有记录或插入新记录(我没有使用 INSERT INTO .. ON DUPLICATE KEY UPDATE 因为检查涉及日期范围,所以我不能真正制作主键的标准)。

我想多次调用此过程(比如说 1000 个左右的批次)。我当然可以使用一个 MySqlConnection 和一个 MySqlCommand 实例并不断更改参数值,并调用 .ExecuteNonQuery()。

我想知道是否有更好的方法来批处理这些调用?

想到的唯一想法是手动构造一个字符串,如'call sp_myprocedure(@parama_1,@paramb_1);call sp_myprocedure(@parama_2,@paramb2);...',然后创建所有适当的参数.我不相信这会比多次调用 .ExecuteNonQuery() 更好。

有什么建议吗?谢谢!

编辑:更多信息
我实际上是在尝试定期存储来自外部数据源的数据。基本上,我正在获取域拍卖的 RSS 提要(来自 Godaddy、pool 等各种来源),并使用此存储过程(我们称之为 sp_storeSale)更新带有拍卖信息的表。现在,在这个存储销售信息的表中,我想保留给定域的销售历史记录,所以我有一个 domain 表和一个 sale 表. sale 表与 domain 表具有多对一的关系。

这是存储过程:

    -- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE PROCEDURE `DomainFace`.`sp_storeSale` 
(
    middle VARCHAR(63),
    extension VARCHAR(10),
    brokerId INT,
    endDate DATETIME,
    url VARCHAR(500),
    category INT,
    saleType INT,
    priceOrBid DECIMAL(10, 2),
    currency VARCHAR(3)    
)
BEGIN
    DECLARE existingId BIGINT DEFAULT NULL;
    DECLARE domainId BIGINT DEFAULT 0;

    SET @domainId = fn_getDomainId(@middle, @extensions);

    SET @existingId = (
        SELECT id FROM sale
        WHERE 
            domainId = @domainId
            AND brokerId = @brokerId
            AND UTC_TIMESTAMP() BETWEEN startDate AND endDate
    );

    IF @existingId IS NOT NULL THEN
        UPDATE sale SET
            endDate = @endDate,
            url = @url,
            category = @category,
            saleType = @saleType,
            priceOrBid = @priceOrBid,
            currency = @currency
        WHERE
            id = @existingId;
    ELSE
        INSERT INTO sale (domainId, brokerId, startDate, endDate, url,
                category, saleType, priceOrBid, currency)
            VALUES (@domainId, @brokerId, UTC_TIMESTAMP(), @endDate, @url,
                @category, @saleType, @priceOrBid, @currency);
    END IF;
END

如您所见,我基本上是在寻找未“过期”但具有相同域和经纪人的现有记录,在这种情况下,我假设拍卖尚未结束,并且数据是更新现有的拍卖。否则,我假设拍卖结束,这是一个历史记录,而我得到的数据是新的拍卖,所以我创建了一个新记录。

希望这能清除我想要实现的目标:)

【问题讨论】:

    标签: c# .net mysql sql


    【解决方案1】:

    我不完全确定您要做什么,但这听起来有点与家务或维护有关,所以我不会因为发布以下建议而感到羞耻。

    为什么不将所有逻辑移入数据库并在服务器端进行处理? 以下示例使用光标(震惊/恐怖),但在这种情况下使用它们是完全可以接受的。

    如果您可以完全避免使用游标 - 很好,但我建议的要点是将逻辑从应用程序层移回数据层以节省往返行程。您将调用以下 sproc 一次,它会在一次调用中处理整个数据范围。

    call house_keeping(curdate() - interval 1 month, curdate());
    

    此外,如果您能提供更多关于您正在尝试做的事情的信息,我们可能会建议其他方法。

    示例存储过程

    drop procedure if exists house_keeping;
    
    delimiter #
    
    create procedure house_keeping
    (
    in p_start_date date,
    in p_end_date date
    )
    begin
    
    declare v_done tinyint default 0;
    declare v_id int unsigned;
    declare v_expired_date date;
    
    declare v_cur cursor for 
      select id, expired_date from foo where 
        expired_date between p_start_date and p_end_date;
    
    declare continue handler for not found set v_done = 1;
    
    open v_cur;
    
    repeat
        fetch v_cur into v_id, v_expired_date;
    
        /*
        if <some condition> then
          insert ...
        else
          update ...
        end if;
        */
    
    until v_done end repeat;
    close v_cur;
    
    end #
    
    delimiter ; 
    

    以防你认为我对建议你可能想阅读的游标完全生气 Optimal MySQL settings for queries that deliver large amounts of data?

    希望这会有所帮助:)

    【讨论】:

    • 谢谢,我在我的问题中添加了更多信息。我没有反对游标,我只是想在短时间内存储大量记录的数据。至少,我每小时可能会存储大约 100,000 条记录。其中一些将是更新,一些将是新记录。
    猜你喜欢
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 2016-09-01
    相关资源
    最近更新 更多