Esempio n. 1
0
        /// <summary>备份单表数据,抽取数据和写入文件双线程</summary>
        /// <remarks>
        /// 最大支持21亿行
        /// </remarks>
        /// <param name="table">数据表</param>
        /// <param name="stream">目标数据流</param>
        /// <returns></returns>
        public virtual Int32 Backup(IDataTable table, Stream stream)
        {
            using var span = Tracer?.NewSpan("db:Backup", table.Name);

            // 并行写入文件,提升吞吐
            var writeFile = new WriteFileActor
            {
                Stream = stream,

                // 最多同时堆积数
                BoundedCapacity = 4,
                TracerParent    = span,
                Tracer          = Tracer,
                Log             = Log,
            };

            var tableName = Dal.Db.FormatName(table);
            var sb        = new SelectBuilder {
                Table = tableName
            };
            var connName = Dal.ConnName;

            var extracer = GetExtracter(table);

            // 总行数
            writeFile.Total = Dal.SelectCount(sb);
            WriteLog("备份[{0}/{1}]开始,共[{2:n0}]行,抽取器{3}", table, connName, writeFile.Total, extracer);

            // 临时关闭日志
            var old = Dal.Db.ShowSQL;

            Dal.Db.ShowSQL      = false;
            Dal.Session.ShowSQL = false;

            var total = 0;
            var sw    = Stopwatch.StartNew();

            try
            {
                foreach (var dt in extracer.Fetch())
                {
                    var row   = extracer.Row;
                    var count = dt.Rows.Count;
                    WriteLog("备份[{0}/{1}]数据 {2:n0} + {3:n0}", table, connName, row, count);
                    if (count == 0)
                    {
                        break;
                    }

                    // 字段名更换为属性名
                    for (var i = 0; i < dt.Columns.Length; i++)
                    {
                        var dc = table.GetColumn(dt.Columns[i]);
                        if (dc != null)
                        {
                            dt.Columns[i] = dc.Name;
                        }
                    }

                    // 进度报告、消费数据
                    OnProcess(table, row, dt, writeFile);

                    total += count;
                }

                // 通知写入完成
                writeFile.Stop(-1);
            }
            catch (Exception ex)
            {
                span?.SetError(ex, table);
                throw;
            }
            finally
            {
                Dal.Db.ShowSQL      = old;
                Dal.Session.ShowSQL = old;
            }

            sw.Stop();
            var ms = sw.Elapsed.TotalMilliseconds;

            WriteLog("备份[{0}/{1}]完成,共[{2:n0}]行,耗时{3:n0}ms,速度{4:n0}tps", table, connName, total, ms, total * 1000L / ms);

            // 返回总行数
            return(total);
        }