遍历计算机名列表匹配脚本异常:全设0且运行缓慢求助
嘿,我帮你捋捋这个脚本的问题,顺便给你几个靠谱的修复方案~
问题根源分析
1. 全表更新导致最终全为0
你的内层foreach循环里,执行UPDATE语句时没有加WHERE条件!这意味着每一次循环都会把inv表的所有行的amp字段全部覆盖一遍。哪怕某次匹配成功把某行设成了1,下一次遇到不匹配的主机名时,又会把所有行(包括刚设为1的那行)改回0,最后自然全是0。
2. 嵌套循环+高频数据库请求导致速度极慢
你现在的逻辑是:
- 遍历ad表的每台电脑,先插入一行到inv表
- 再遍历amp表的每台电脑,每遍历一次就发一次UPDATE请求
如果ad有100台、amp有100台,那就是100次INSERT + 10000次UPDATE,数据库请求次数直接爆炸,速度快才怪。
3. 隐藏的SQL注入风险
直接把$adcompName拼进SQL语句里,如果电脑名带单引号或者特殊字符,脚本会直接报错,甚至存在SQL注入风险。
修复方案
方案一:用纯SQL完成推荐!效率拉满
其实这个需求完全可以交给数据库一次性搞定,根本不需要PowerShell做嵌套循环,速度快到飞起:
-- 清空inv表(如果需要全量更新的话) TRUNCATE TABLE inv; -- 一次性插入所有ad电脑名,并自动匹配amp状态 INSERT INTO inv (ComputerName, amp) SELECT ad.ComputerName, CASE WHEN amp.HostName IS NOT NULL THEN '1' ELSE '0' END AS amp FROM ad LEFT JOIN amp ON ad.ComputerName = amp.HostName;
如果inv表已经有数据,只需要更新amp字段的话,用这个:
UPDATE inv JOIN ad ON inv.ComputerName = ad.ComputerName LEFT JOIN amp ON ad.ComputerName = amp.HostName SET inv.amp = CASE WHEN amp.HostName IS NOT NULL THEN '1' ELSE '0' END;
方案二:优化PowerShell脚本如果一定要用PowerShell
如果必须用PowerShell实现,我们可以先把amp的主机名存进哈希集合(快速查找),再减少数据库请求次数:
# 先把amp的所有主机名存入哈希集合,实现O(1)快速查找 $ampHosts = [System.Collections.Generic.HashSet[string]]::new() $ampcompdata = Invoke-MySqlQuery -query "SELECT HostName FROM amp" foreach ($item in $ampcompdata) { [void]$ampHosts.Add($item.HostName) } # 遍历ad表数据,逐个处理并插入(或更新) $adcompdata = Invoke-MySqlQuery -query "SELECT ComputerName FROM ad" foreach ($adcompitem in $adcompdata) { $adcompName = $adcompitem.ComputerName $matchStatus = if ($ampHosts.Contains($adcompName)) { '1' } else { '0' } # 用参数化查询插入数据,避免SQL注入 Invoke-MySqlQuery -Query "INSERT INTO inv(ComputerName, amp) VALUES(@name, @amp)" -Parameters @{ name = $adcompName amp = $matchStatus } # 如果是更新已有数据,记得加WHERE条件指定行 # Invoke-MySqlQuery -Query "UPDATE inv SET amp = @amp WHERE ComputerName = @name" -Parameters @{ # name = $adcompName # amp = $matchStatus # } Write-Host "处理完成:$adcompName,匹配状态:$(if ($matchStatus -eq '1') {'匹配'} else {'不匹配'})" }
这个优化的核心点:
- 哈希集合让主机名匹配速度从O(n)变成O(1)
- 每个ad电脑只触发1次数据库请求,总请求数从O(n*m)降到O(n+m)
- 参数化查询避免了SQL注入,还能处理带特殊字符的电脑名
- 每次操作都指定了目标行,不会误改其他数据
关于调试时匹配项仍为0的原因
当你匹配到"015598793153"时,执行的UPDATE inv SET amp = '1'会把全表的amp都改成1,但内层循环还会继续遍历amp表的其他主机名,下一次不匹配时,又会执行UPDATE inv SET amp = '0'再次全表覆盖,所以那行最后又被改回0了。
内容的提问来源于stack exchange,提问作者claeys
相关产品推荐
相关产品推荐

