BITMAP CONVERSION FROM ROWIDS

本文详细解析了在Oracle SQL执行计划中遇到的BITMAPCONVERSIONFROMROWIDS现象,解释了其原理,并提供了解决方案。重点在于通过实例分析如何识别并优化不适当的索引,从而提升执行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在有些执行计划中,可以会看到 BITMAP CONVERSION FROM ROWIDS这样的东东,也许你会感觉奇怪,我没有使用位图索引怎么出现了bitmap。
我通过一个sql和大家分析下原因:
sql语句为:

SELECT *
   FROM ( SELECT a.*, ROWNUM rn
           FROM SELECT module_no, MAX (id) AS id
                     FROM vasoa.tab_moa_historypage t
                    WHERE t.company_id = :1 AND t.user_id = :2 AND t.TYPE = :3
                 GROUP BY module_no
                 ORDER BY id DESC ) a
          WHERE ROWNUM <= :4) b
WHERE b.rn >= :5

执行计划为:

表结构为:

目前索引情况:

通过观察执行计划的图片可以发现,使用了 BITMAP CONVERSION FROM ROWIDS,其目的是:.oracle将btree索引中获得的rowid信息通过BITMAP CONVERSION FROM ROWIDS的步骤转换成bitmap进行匹配,然后匹配完成后通过BITMAP CONVERSION TO ROWIDS再转换出rowid获得数据或者回表获得数据。这种想象出现的原因为:oracle的cbo是根据cost来决定大小来选择合适的执行计划,当它计算获得通过bitmap的方式执行的时候cost会更小,它就会选择使用这样的执行计划。一般出现这样的情况,都是因为对表建立的不适当的index导致,特别是对表中的唯一度不高的列建立了index,然后oracle就有可能选择两个这样的列转为为bitmap来执行。根据oracle的执行计划,肯定是cost最小的,但是它很多时候忽略了一致性读等其他条件,导致这个执行计划并非像oracle想象的那样最优,因为把btree index转为为bitmap index执行,需要消耗更多的cpu,特别是在cpu比较紧张的系统中,所以这样的情况如果发生在oltp系统中,一般都需要解决。
本例的解决办法是删除唯一度低的index,建立组合index。分别删除COMPANY_ID与USER_ID上的index,建立COMPANY_ID和USER_ID的组合index,执行计划如下:

 

转载:http://www.xifenfei.com/1531.html

<think>我们正在讨论C#中Bitmap.FromFile加载文件后如何覆盖原文件的问题。根据用户提供的引用和问题,用户可能在使用Bitmap.FromFile加载图片后,尝试覆盖原文件时遇到了问题(例如文件被占用无法覆盖)。关键点:当使用Bitmap.FromFile方法加载图像时,文件会被锁定,直到Bitmap对象被释放。因此,在Bitmap对象存在期间,无法覆盖或删除原文件。解决方案:1.复制图像数据到新的Bitmap对象,然后释放原文件。2.使用流来加载图像,这样可以控制文件的锁定行为。根据引用[1]中的做法:先加载图像,然后克隆,再释放原图像对象。但用户发现即使释放了,文件还是被占用。引用[1]中提到,Clone方法可能仍然关联到原文件路径。因此,我们需要一种更彻底的方法。引用[2]中展示了一个使用Stream加载图像的方法,这样可以在读取后关闭流,从而释放文件锁。因此,推荐方法:使用FileStream打开文件,然后使用Bitmap(Stream)构造函数来创建Bitmap对象,并在使用后及时释放流和Bitmap对象。步骤:1.使用FileStream打开文件(注意使用FileShare.ReadWrite等共享模式,但这里主要是为了读取后关闭流以释放文件)。2.从流创建Bitmap对象。3.确保在完成Bitmap的使用后,释放Bitmap和流(使用using语句)。但是,注意:覆盖原文件需要先释放所有占用该文件的资源。因此,在覆盖之前,必须确保Bitmap对象和流都已经被释放。具体代码示例:假设我们要加载一个图片,修改后保存回原文件:步骤:a.从文件流加载图片(此时文件不会被长时间锁定)。b.处理图片。c.释放图片对象和流(实际上,使用using块会自动释放)。d.然后就可以覆盖原文件了。但是,注意:在保存回原文件时,如果直接使用Save方法覆盖原文件,可能会失败,因为原文件可能还在被占用(虽然我们已经释放了,但可能其他原因)。因此,安全的做法是先保存到一个临时文件,然后删除原文件,再将临时文件重命名为原文件。不过,根据用户需求,我们只需要覆盖原文件。实际上,在释放了所有资源后,我们可以直接覆盖。但为了避免异常,我们可以使用以下方法:方法1:使用流加载,然后释放,再保存(覆盖)原文件。代码示例:```csharpstringfilePath= "原文件路径";//使用流加载图片using(FileStream fs= newFileStream(filePath, FileMode.Open, FileAccess.Read)) {using(Bitmapbmp= newBitmap(fs)){//在这里对bmp进行处理(例如修改图片)// ...处理代码 ...//注意:此时不能直接保存到原文件,因为流fs还在打开状态(尽管我们会在using块结束后关闭,但保存操作不能在using块内部覆盖原文件,因为fs还在使用中)//所以,我们先将修改后的图片保存到一个临时文件string tempPath =Path.GetTempFileName();bmp.Save(tempPath,System.Drawing.Imaging.ImageFormat.Jpeg); //根据实际格式保存}//释放bmp}//关闭并释放fs//此时原文件已经释放,我们可以用临时文件覆盖原文件File.Delete(filePath);File.Move(tempPath,filePath); ```但是,上述方法使用了临时文件。如果我们不想用临时文件,也可以尝试在释放所有资源后,再保存回原文件。但是,由于在using块内部,原文件流已经打开,所以不能在using块内部保存回原文件(会提示文件被占用)。因此,我们可以在using块外部再创建一个新的Bitmap对象(从内存数据)?或者,我们可以将修改后的Bitmap保存到内存流,然后在using块外部保存到文件。方法2:在内存中处理,然后覆盖原文件(无需临时文件,但需要足够内存)```csharpstring filePath ="原文件路径";Bitmap modifiedBmp;//使用流加载图片using (FileStreamfs =new FileStream(filePath,FileMode.Open,FileAccess.Read)){using (Bitmap bmp =new Bitmap(fs)){//在这里对bmp进行处理(例如修改图片)// ...处理代码 ...//将修改后的图像复制到新的Bitmap对象(这样我们就可以在释放原Bitmap后继续使用图像数据)modifiedBmp =new Bitmap(bmp);//注意:这里创建了一个新的Bitmap,不依赖于文件流} //释放bmp} //关闭并释放fs//现在原文件已经释放,我们可以将modifiedBmp保存回原文件using (modifiedBmp)//确保modifiedBmp也会被释放{modifiedBmp.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg); //覆盖原文件}```注意:方法2中,我们通过克隆原图像(newBitmap(bmp))创建了一个新的Bitmap对象,这样它就不依赖于原来的文件流。然后在原文件流关闭后,我们就可以将新的Bitmap保存回原文件。但是,方法2有一个缺点:如果原图像很大,那么克隆操作会占用双倍内存。方法3:使用内存流(推荐,可以避免文件锁,同时避免双倍内存占用?但实际上,内存流也会占用内存,但可以避免临时文件)我们可以将修改后的图像保存到内存流,然后在文件流关闭后,将内存流写入原文件。但是,这样需要将整个图像数据加载到内存中,对于大图像可能不太合适。综合来看,方法1(使用临时文件)是较为通用的做法,因为磁盘操作相对安全,且不会占用过多内存。根据引用[3]中的调用示例,用户可能是在WPF中操作,但Bitmap是System.Drawing中的,在WPF中也可以使用,但要注意跨线程问题。不过用户问题没有涉及线程。因此,总结步骤:1.使用FileStream打开文件,创建Bitmap。2.处理图像。3.将处理后的图像保存到临时文件(在FileStream和Bitmap释放后)。4.删除原文件,将临时文件重命名为原文件。或者,如果内存足够,使用方法2:在释放文件流后,使用一个独立的Bitmap对象(不依赖于文件)保存回原文件。用户问题:如何覆盖原文件。因此,我们给出两种方法供选择。注意:在覆盖原文件时,要确保程序有足够的权限。另外,引用[4]中提到了文件操作(写入日志),但与我们这里的问题关系不大。因此,回答如下:在C#中,使用Bitmap.FromFile加载图像后,文件会被锁定。要覆盖原文件,必须先释放Bitmap对象。但是,即使释放了,有时也会因为文件锁未及时释放而导致覆盖失败。因此,推荐使用FileStream来加载图像,并在处理完成后关闭流以释放文件锁。然后,再保存图像到原文件。以下是两种实现方式: **方式一:使用临时文件(安全可靠)** ```csharpstringoriginalFilePath= @"C:\path\to\your\image.jpg";//加载图像并处理using(FileStream fs= newFileStream(originalFilePath,FileMode.Open,FileAccess.Read)){using (Bitmap bmp =new Bitmap(fs)){//对图像进行处理,例如调整大小、修改等// ...//保存到临时文件stringtempFile= Path.GetTempFileName();bmp.Save(tempFile, System.Drawing.Imaging.ImageFormat.Jpeg);}//释放Bitmap}//关闭文件流//现在原文件已解锁,用临时文件替换原文件File.Delete(originalFilePath);File.Move(tempFile,originalFilePath); ```**方式二:创建独立Bitmap对象(内存足够时使用)** ```csharpstringoriginalFilePath= @"C:\path\to\your\image.jpg";Bitmap modifiedBitmap= null; using(FileStream fs= newFileStream(originalFilePath,FileMode.Open,FileAccess.Read)){using (Bitmap originalBmp =new Bitmap(fs)){//对图像进行处理// ...//创建新的Bitmap对象(独立于文件流)modifiedBitmap =new Bitmap(originalBmp);}//释放originalBmp} //关闭文件流//保存回原文件if(modifiedBitmap !=null){using (modifiedBitmap){modifiedBitmap.Save(originalFilePath, System.Drawing.Imaging.ImageFormat.Jpeg);} }```注意事项:-确保在保存图像时使用正确的图像格式(如Jpeg,Png等)。-如果处理过程中出现异常,应确保资源被正确释放(使用using语句可以保证)。 -对于大文件,临时文件或内存占用可能会影响性能,请根据实际情况选择。这样,就可以在加载图像后成功覆盖原文件。根据要求,生成相关问题:§§相关问题§§1.在C#中,Bitmap.FromFile和Bitmap(Stream)有什么区别? 2.如何避免C#中图像处理时文件被锁定的问题? 3.在C#中处理大图像文件时,如何优化内存使用?</think>### C# Bitmap.FromFile 覆盖原文件的解决方案 在 C# 中使用 `Bitmap.FromFile` 加载图像后直接覆盖原文件会遇到文件锁定的问题,因为 GDI+ 会保持文件句柄打开状态。以下是两种可靠解决方案: #### 解决方案 1:使用内存流复制图像(推荐) ```csharp string filePath = @"C:\test.jpg"; // 1. 读取文件到内存流 byte[] imageData; using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { imageData = new byte[fs.Length]; fs.Read(imageData, 0, (int)fs.Length); } // 2. 从内存流创建 Bitmap using (MemoryStream ms = new MemoryStream(imageData)) using (Bitmap bmp = new Bitmap(ms)) { // 3. 修改图像(示例:旋转90度) bmp.RotateFlip(RotateFlipType.Rotate90FlipNone); // 4. 覆盖原文件(先释放锁再保存) bmp.Save(filePath, ImageFormat.Jpeg); // 自动释放文件锁 } ``` #### 解决方案 2:使用临时文件中转 ```csharp string filePath = @"C:\test.jpg"; string tempPath = Path.GetTempFileName(); using (Bitmap bmp = new Bitmap(filePath)) { // 修改图像 using (Graphics g = Graphics.FromImage(bmp)) { g.DrawString("Text", new Font("Arial", 20), Brushes.Red, new Point(10,10)); } // 保存到临时文件 bmp.Save(tempPath, ImageFormat.Png); } // 覆盖原文件(文件锁已释放) File.Delete(filePath); File.Move(tempPath, filePath); ``` #### 关键注意事项: 1. **文件锁定机制** `Bitmap.FromFile()` 会锁定文件直到 `Dispose()` 被调用[^1]。直接覆盖会引发 `System.IO.IOException`(文件被占用)。 2. **内存流优势** 内存流方案完全避免文件锁定,适合高频操作: ```csharp // 正确释放资源示例 using (var ms = new MemoryStream(File.ReadAllBytes(filePath))) using (var bmp = new Bitmap(ms)) { // 操作图像 } // 自动释放锁 ``` 3. **格式兼容性** 保存时需指定原格式(如 JPEG、PNG),否则可能损坏文件: ```csharp bmp.Save(filePath, GetImageFormat(filePath)); // 获取格式的辅助函数 ImageFormat GetImageFormat(string path) { string ext = Path.GetExtension(path).ToLower(); return ext switch { ".jpg" or ".jpeg" => ImageFormat.Jpeg, ".png" => ImageFormat.Png, _ => ImageFormat.Png }; } ``` 4. **异常处理** 添加文件访问异常处理: ```csharp try { // 文件操作代码 } catch (IOException ex) { MessageBox.Show($"文件被占用: {ex.Message}"); } ``` #### 引用说明: [^1]: 使用 `Bitmap.FromFile` 后文件会被锁定,直到 Bitmap 对象被释放。通过内存流或克隆可解除锁定[^1]。 [^2]: 文件操作需确保目录存在,临时文件路径应通过 `Path.GetTempFileName()` 生成[^2]。 [^3]: 实际应用中建议封装为独立方法,参考图像处理的最佳实践[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值