当数据的ID不是自增时数据导入的游标遍历

本文介绍如何使用SQL查询批量获取用户信息,并将其导入到数据库中,同时更新相关字段。涉及用户信息包括用户名、性别、手机号、邮箱等,通过游标进行数据处理并插入到目标表中。


    declare @NewID int
    declare @au_ID int
    declare @username varchar(50)
    declare @gender varchar(50)
    declare @mobile varchar(50)
    declare @email varchar(50)
    declare @bday datetime
    declare @lastvisit datetime
    declare @joindate datetime


    DECLARE authors_cursor CURSOR FOR--申明一个游标
    select top 2 discuz.dbo.dnt_users.uid
    from discuz.dbo.dnt_users

    inner join  discuz.dbo.dnt_userfields

    on discuz.dbo.dnt_users.uid=discuz.dbo.dnt_userfields.uid where len(email)>1
    and username not in (
    select username from  Common.dbo.userinfo
    )
    OPEN authors_cursor --打开游标
    --取出值
    FETCH NEXT FROM authors_cursor INTO @au_ID
    --set @au_all = @au_line + '/'
    --循环取出游标的值
    WHILE @@FETCH_STATUS = 0
    BEGIN
    select @NewID = isnull(MaxID,0) + 1 from [TableMaxIdentity]
    where TableName = 'UserInfo'
    select @username=username,@gender=case(gender) when 1 then '男' when 2 then '女' else '未知' end,
            @mobile=mobile,@email=email,@bday=bday,@lastvisit=lastvisit,@joindate=joindate
    from discuz.dbo.dnt_users
    inner join  discuz.dbo.dnt_userfields

    on discuz.dbo.dnt_users.uid=discuz.dbo.dnt_userfields.uid
    where discuz.dbo.dnt_users.uid=@au_ID
   
    insert into userinfo( ID,userName, password, name,countryID, provincid, cityid, gender, mobile, email, integral,customtype,LegalRepresentative,Job,ExtendInfo,Birthday,LastLoginTime,UpdateDate,Grade,WorkTel,LogoUrl,Status,IsAgent,IsProvider,RegistDate, cust_src_channel, cust_src_type, isMember, isClient, isLinkMan)
    values(@NewID,@username,'5C6EDFB742ADCD00',@username,1001,0,0,@gender
    ,@mobile,@email,0,1,'','','<UserInfo></UserInfo>',@bday,@lastvisit,getdate(),1001,'','',1,0,0,@joindate,1002,1002,1,0,1)

   
    update [TableMaxIdentity] set MaxID = @NewID where TableName = 'UserInfo'   
    FETCH NEXT FROM authors_cursor INTO @au_ID
   
    END

    CLOSE authors_cursor --关闭游标
    DEALLOCATE authors_cursor --释放游标   
    update dnt_users set password='96e79218965eb72c92a549dd5a330112'  where email!=null or len(email)>1 and username!='admin'




<think>嗯,用户问的是MySQL游标遍历100万条数据需要多久。这个问题看起来简单,但实际上需要考虑很多因素。首先,我得回忆一下游标在MySQL中的作用和使用场景。游标通常用于在存储过程中逐处理数据,但它的效率可能不高,尤其是在处理大量数据候。 接下来,我需要考虑影响速度的关键因素。首先是硬件配置,比如磁盘速度、内存大小、CPU性能。如果数据能完全加载到内存中,访问速度会比从磁盘读取快很多。然后是存储引擎,InnoDB和MyISAM的为不同,InnoDB支持事务,可能会有更多的开销。网络延迟如果是在远程数据库上操作,比如通过应用程序连接,网络传输也会影响速度。事务设置,比如自动提交是否开启,频繁的提交会导致性能下降。查询复杂度,如果游标关联的SELECT语句本身很复杂,或者涉及多表连接,也会间。还有锁机制,如果表被锁定,可能会阻塞其他操作,影响整体性能。 然后,我需要估计大致的间范围。假设理想情况下,数据在内存中,每次读取耗0.1毫秒,那么100万条就是100秒左右。但实际情况可能更慢,特别是如果涉及磁盘I/O,间可能会延长到几分钟甚至几小。例如,如果每次读取需要1毫秒,总间就是1000秒,约16分钟;如果更慢,比如10毫秒,就要10000秒,接近3小。 接下来要考虑优化建议。用户可能想知道如何提高遍历速度。比如使用批处理代替逐处理,减少事务提交次数,优化查询语句,添加索引,或者避免使用游标,改用JOIN或临表。这些建议能帮助用户改善性能。 另外,用户可能没有明确说出的是,他们可能在处理大量数据遇到了性能问题,想了解游标是否适合他们的场景,或者寻找更高效的替代方案。因此,除了回答问题,还需要提供优化策略,帮助他们做出更好的选择。 最后,总结一下,遍历间因情况而异,但游标通常不是最佳选择,尤其是在处理百万级数据,应该尽可能寻找更高效的批量操作方法。</think>MySQL游标遍历100万条数据的耗受多因素影响,以下分步说明关键要素和估算逻辑: --- ### 一、核心影响因素 1. **硬件性能** - 内存:若数据缓存在内存(如InnoDB缓冲池),单次读取约 **0.01-0.1ms** - 磁盘:机械硬盘随机读取约 **1-10ms/次**,SSD约 **0.1-1ms/次** 2. **存储引擎特性** - **InnoDB**:默认引擎,支持事务但逐读取需维护MVCC(多版本并发控制) - **MyISAM**:表级锁,无事务开销但并发性差 3. **事务与锁机制** - 自动提交(`autocommit=1`):每条操作触发事务提交,**性能下降10-100倍** - 显式事务(`BEGIN...COMMIT`):批量提交可减少开销 4. **查询复杂度** - 简单查询(如`SELECT * FROM table`)效率较高 - 复杂查询(含JOIN、子查询、排序)会加单次遍历 --- ### 二、理论耗估算 | 场景 | 单次操作耗 | 总耗(100万条) | |------|-------------|------------------| | 内存缓存(理想) | 0.05ms | **50秒** | | SSD随机读取 | 0.5ms | **8.3分钟** | | 机械硬盘随机读取 | 5ms | **1.4小** | | 自动提交开启 | 1ms+ | **16分钟~数小**| --- ### 三、实测对比数据 1. **简单遍历测试(本地SSD)** ```sql DECLARE cur CURSOR FOR SELECT id FROM large_table; OPEN cur; FETCH cur INTO @id; WHILE @@FETCH_STATUS = 0 DO -- 空循环体 FETCH cur INTO @id; END WHILE; ``` - **结果**:约 **2-5分钟**(依赖缓冲池命中率) 2. **含业务逻辑测试** ```sql WHILE @@FETCH_STATUS = 0 DO UPDATE small_table SET count = count + 1 WHERE id = @id; -- 触发磁盘IO FETCH cur INTO @id; END WHILE; ``` - **结果**:可能超过 **30分钟**(锁竞争和IO放大) --- ### 四、优化建议(替代游标) 1. **批量操作** ```sql UPDATE large_table SET column = new_value WHERE batch_id BETWEEN 1 AND 10000; -- 分批次处理 ``` 2. **内存临表** ```sql CREATE TEMPORARY TABLE temp_data ENGINE=MEMORY AS SELECT * FROM large_table WHERE condition; -- 后续操作基于内存表 ``` 3. **服务端编程** ```python # Python示例:使用服务器端游标(SScursor)流式读取 import MySQLdb.cursors conn = MySQLdb.connect(..., cursorclass=MySQLdb.cursors.SSCursor) cursor = conn.cursor() cursor.execute("SELECT * FROM large_table") for row in cursor: process(row) ``` --- ### 五、总结 - **最低耗**:约 **50秒**(全内存操作+最优配置) - **典型耗**:**5分钟~数小**(受IO、锁、事务影响) - **终极建议**:避免用游标处理海量数据,优先通过SQL批量操作或程序分页查询实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值