我们有一个大约3.8亿条记录的大表。我们需要删除超过2013年1月1日的前2.5亿条记录。我用谷歌搜索了一些方法,但我不满意。最常见和最快的方式是这样的:
create table newbig_table unrecoverable as
select * from oldhuge_table
where <condition is reverse of delete condition>
最后将新表重命名为原名称,但连续插入的新记录将是什么?
主要问题是;该表是一个在线表,由许多代理使用。所以我需要通过不减慢系统速度和不影响新记录来删除。我自己试过这个方法:
using (SqlConnection connData = new SqlConnection("Data Source=xxx;User ID=xxx;password=xxx;Initial Catalog=xxx"))
{
connData.Open();
int cnt = 0;
long total = 0;
long startID = 1039142601;
long endID = 1385795368;
long recCount = endID - startID;
cnt++;
long delRange = 400; //deletes 400 by 400
for (long i = 1; i < endID; i++)
{
startTime = DateTime.Now;
string deleteSql = "delete from DivaSessionFlowLog " +
" where ID >= " + startID.ToString() +
" and ID <= " + (startID + delRange).ToString();
int strID = (int)((new SqlCommand(deleteSql, connData)).ExecuteNonQuery());
total = total + strID;
Console.WriteLine(i.ToString() + ":" + strID.ToString() + " OK DelCnt:" + total.ToString() + " ID:" + startID.ToString() + " Rest:" + String.Format("{0:#,#}", (recCount - total)) + " Time:" + DateTime.Now.ToString("HH':'mm':'ss"));
Thread.Sleep(200);
startID = startID + delRange;
i = startID;
}
为了不使系统变慢,系统程序休眠200毫秒。但是,我计算的完成时间大约是2周。总之,我需要找到;
- 快速
- 不会使数据库变慢
- 不影响连续插入的新记录
从一个大表中删除多行的方法。有什么建议吗?
最好的方法是对表进行分区,这样就可以删除旧的分区。
但是,如果您需要修改表,并且不要忘记表可能具有特权、索引、触发器等,并且您需要在整个过程中保持它可用,那么您需要使用DBMS_Redefinition。
同样,UNRECOVERABLE是旧的语法,但是您不会想要现代的等价语法,因为如果您在系统上发生媒体故障,您将丢失表和数据。
按日期对表进行分区将大有帮助。删除特定分区的内容要比逐个删除行快得多。
看看http://www.oracle-base.com/articles/misc/partitioning-an-existing-table.php;本文描述了如何从非分区表移动到分区表。
将delRange
从400改为40000或400000
根据我的计算,您的过程将在Thread.Sleep(200)
中花费5.015天。并且有额外的时间用于网络,写入到控制台等。在块中修改数据并非总是可以避免的,但您至少应该尝试使用更大的块。
正如其他人提到的,分区可能非常有用。但是分区有很多缺点,如果这是一个罕见的过程,那么简单的方式可能是值得的。