public List <Row> show() { bind(null); // TBD: route to optimizer here QueryOption queryOpt = new QueryOption(); physicPlan_ = logicPlan_.DirectToPhysical(queryOpt); logicPlan_.ResolveColumnOrdinal(outputs_); // actual execution var finalplan = new PhysicCollect(physicPlan_); physicPlan_ = finalplan; var context = new ExecContext(queryOpt); Console.WriteLine(physicPlan_.Explain()); finalplan.ValidateThis(); var code = finalplan.Open(context); code += finalplan.Exec(null); code += finalplan.Close(); return(finalplan.rows_); }
static void Main(string[] args) { Catalog.Init(); string sql = ""; if (false) { JOBench.CreateTables(); sql = File.ReadAllText("../../../jobench/10a.sql"); goto doit; } if (false) { Tpch.CreateTables(); Tpch.LoadTables("0001"); //Tpch.CreateIndexes(); Tpch.AnalyzeTables(); sql = File.ReadAllText("../../../tpch/q20.sql"); goto doit; } if (false) { Tpcds.CreateTables(); Tpcds.LoadTables("tiny"); Tpcds.AnalyzeTables(); // 1, 2,3,7,10, // long time: 4 bad plan // 6: distinct not supported, causing wrong result sql = File.ReadAllText("../../../tpcds/q7.sql"); goto doit; } doit: sql = "select a2,b2,c2,d2 from ad, bd, cd, dd where a2=b2 and c2 = b2 and c2=d2 order by a2"; sql = "select count(*) from ast group by tumble(a0, interval '10' second)"; sql = "select round(a1, 10), count(*) from a group by round(a1, 10)"; sql = "select count(*) from a group by round(a1, 10)"; sql = "select count(*) from ast group by hop(a0, interval '5' second, interval '10' second)"; sql = "select round(a1, 10) from a group by a1;"; sql = "select abs(-a1*2), count(*) from a group by round(a1, 10);"; sql = "select abs(-a1*2), count(*) from a group by a1;"; sql = "select tumble_start(a0, interval '10' second), tumble_end(a0, interval '10' second), count(*) from ast group by tumble(a0, interval '10' second)"; var datetime = new DateTime(); datetime = DateTime.Now; var stopWatch = new Stopwatch(); stopWatch.Start(); // query options might be conflicting or incomplete Console.WriteLine(sql); var a = RawParser.ParseSingleSqlStatement(sql); ExplainOption.show_tablename_ = false; a.queryOpt_.profile_.enabled_ = true; a.queryOpt_.optimize_.enable_subquery_unnest_ = false; a.queryOpt_.optimize_.remove_from_ = false; a.queryOpt_.optimize_.use_memo_ = true; a.queryOpt_.optimize_.enable_cte_plan_ = false; a.queryOpt_.optimize_.use_codegen_ = false; a.queryOpt_.optimize_.memo_disable_crossjoin_ = false; a.queryOpt_.optimize_.memo_use_joinorder_solver_ = false; a.queryOpt_.explain_.show_output_ = true; a.queryOpt_.explain_.show_id_ = false; a.queryOpt_.explain_.show_cost_ = a.queryOpt_.optimize_.use_memo_; // -- Semantic analysis: // - bind the query a.queryOpt_.optimize_.ValidateOptions(); a.Bind(null); // -- generate an initial plan var rawplan = a.CreatePlan(); Console.WriteLine("***************** raw plan *************"); Console.WriteLine(rawplan.Explain()); // -- optimize the plan PhysicNode phyplan = null; if (a.queryOpt_.optimize_.use_memo_) { Console.WriteLine("***************** optimized plan *************"); var optplan = a.SubstitutionOptimize(); Console.WriteLine(optplan.Explain(a.queryOpt_.explain_)); a.optimizer_.InitRootPlan(a); a.optimizer_.OptimizeRootPlan(a, null); Console.WriteLine(a.optimizer_.PrintMemo()); phyplan = a.optimizer_.CopyOutOptimalPlan(); Console.WriteLine(a.optimizer_.PrintMemo()); Console.WriteLine("***************** Memo plan *************"); Console.WriteLine(phyplan.Explain(a.queryOpt_.explain_)); } else { // -- optimize the plan Console.WriteLine("-- optimized plan --"); var optplan = a.SubstitutionOptimize(); Console.WriteLine(optplan.Explain(a.queryOpt_.explain_)); // -- physical plan Console.WriteLine("-- physical plan --"); phyplan = a.physicPlan_; Console.WriteLine(phyplan.Explain(a.queryOpt_.explain_)); } // -- output profile and query result Console.WriteLine("-- profiling plan --"); var final = new PhysicCollect(phyplan); a.physicPlan_ = final; ExecContext context = a.CreateExecContext(); final.ValidateThis(); if (a is SelectStmt select) { select.OpenSubQueries(context); } var code = final.Open(context); code += final.Exec(null); code += final.Close(); if (a.queryOpt_.optimize_.use_codegen_) { CodeWriter.WriteLine(code); Compiler.Run(Compiler.Compile(), a, context); } Console.WriteLine(phyplan.Explain(a.queryOpt_.explain_)); stopWatch.Stop(); Console.WriteLine("RunTime: " + stopWatch.Elapsed); Console.ReadKey(); }
static void Main(string[] args) { Catalog.Init(); string sql = ""; if (args.Length != 0) { sql = args[0]; } #pragma warning disable CS0162 // Unreachable code detected // The warnings are annoying, so using a pragma to suppress them. if (false) { JOBench.CreateTables(); var stats_fn = "../../../../jobench/statistics/jobench_stats"; Catalog.sysstat_.read_serialized_stats(stats_fn); sql = File.ReadAllText("../../../../jobench/10a.sql"); goto doit; } if (false) { Tpch.CreateTables(); Tpch.LoadTables("0001"); //Tpch.CreateIndexes(); Tpch.AnalyzeTables(); sql = File.ReadAllText("../../../../tpch/q20.sql"); goto doit; } if (false) { //84 sql = File.ReadAllText("../../../../tpcds/q33.sql"); Tpcds.CreateTables(); Tpcds.LoadTables("tiny"); Tpcds.AnalyzeTables(); // long time: 4 bad plan // 6: distinct not supported, causing wrong result // q23, q33, q56, q60: in-subquery plan bug // 10,11,13, 31, 38, 41, 48, 54, 66, 72, 74: too slow goto doit; } #pragma warning restore CS0162 // Unreachable code detected doit: bool convMode = false; // Application Arguments in Project properties seem to be // effective only after rebuilding. // This is a last ditch effort to be able to debug arbitrary // statements without rebuilding the solution. string inputFile = ""; if (sql.Length == 2 && sql == "-i") { convMode = true; } else if (sql.Length == 2 && sql.StartsWith("-f")) { inputFile = args[1]; } else if (sql.Length == 0) { sql = "select * from a tablesample row (2);"; } do { if (convMode == true || (sql.Length == 1 && sql.Equals("-"))) { System.Console.Write("QSQL> "); sql = System.Console.ReadLine(); System.Console.WriteLine(sql); } var datetime = new DateTime(); datetime = DateTime.Now; var stopWatch = new Stopwatch(); stopWatch.Start(); if (inputFile.Length != 0) { // read the file and execute all statements in it. RunSQLFromFile(inputFile); goto done; } // query options might be conflicting or incomplete Console.WriteLine(sql); var a = RawParser.ParseSingleSqlStatement(sql); ExplainOption.show_tablename_ = true; a.queryOpt_.profile_.enabled_ = true; a.queryOpt_.optimize_.enable_subquery_unnest_ = true; a.queryOpt_.optimize_.remove_from_ = true; a.queryOpt_.optimize_.use_memo_ = true; a.queryOpt_.optimize_.enable_cte_plan_ = true; a.queryOpt_.optimize_.use_codegen_ = false; a.queryOpt_.optimize_.memo_disable_crossjoin_ = false; a.queryOpt_.optimize_.memo_use_joinorder_solver_ = false; a.queryOpt_.explain_.show_output_ = true; a.queryOpt_.explain_.show_id_ = true; a.queryOpt_.explain_.show_estCost_ = a.queryOpt_.optimize_.use_memo_; a.queryOpt_.explain_.mode_ = ExplainMode.full; // -- Semantic analysis: // - bind the query a.queryOpt_.optimize_.ValidateOptions(); if (!(a is SelectStmt)) { SQLStatement.ExecSQLList(sql); goto done; } a.Bind(null); // -- generate an initial plan var rawplan = a.CreatePlan(); Console.WriteLine("***************** raw plan *************"); Console.WriteLine(rawplan.Explain()); // -- optimize the plan PhysicNode phyplan = null; if (a.queryOpt_.optimize_.use_memo_) { Console.WriteLine("***************** optimized plan *************"); var optplan = a.SubstitutionOptimize(); Console.WriteLine(optplan.Explain(a.queryOpt_.explain_)); a.optimizer_ = new Optimizer(a); a.optimizer_.ExploreRootPlan(a); phyplan = a.optimizer_.CopyOutOptimalPlan(); Console.WriteLine(a.optimizer_.PrintMemo()); Console.WriteLine("***************** Memo plan *************"); Console.WriteLine(phyplan.Explain(a.queryOpt_.explain_)); } else { // -- optimize the plan Console.WriteLine("-- optimized plan --"); var optplan = a.SubstitutionOptimize(); Console.WriteLine(optplan.Explain(a.queryOpt_.explain_)); // -- physical plan Console.WriteLine("-- physical plan --"); phyplan = a.physicPlan_; Console.WriteLine(phyplan.Explain(a.queryOpt_.explain_)); } // -- output profile and query result Console.WriteLine("-- profiling plan --"); var final = new PhysicCollect(phyplan); a.physicPlan_ = final; ExecContext context = a.CreateExecContext(); final.ValidateThis(); if (a is SelectStmt select) { select.OpenSubQueries(context); } final.Open(context); final.Exec(null); final.Close(); if (a.queryOpt_.optimize_.use_codegen_) { CodeWriter.WriteLine(context.code_); Compiler.Run(Compiler.Compile(), a, context); } Console.WriteLine(phyplan.Explain(a.queryOpt_.explain_)); done: stopWatch.Stop(); Console.WriteLine("RunTime: " + stopWatch.Elapsed); } while (convMode == true); Console.ReadKey(); }
public static void Run(SQLStatement stmt, ExecContext context) { PhysicCollect PhysicCollect108 = stmt.physicPlan_.LocateNode("108") as PhysicCollect; PhysicProfiling PhysicProfiling109 = stmt.physicPlan_.LocateNode("109") as PhysicProfiling; LogicLimit LogicLimit109 = PhysicProfiling109.logic_ as LogicLimit; var filter109 = LogicLimit109.filter_; var output109 = LogicLimit109.output_; PhysicLimit PhysicLimit110 = stmt.physicPlan_.LocateNode("110") as PhysicLimit; LogicLimit LogicLimit110 = PhysicLimit110.logic_ as LogicLimit; var filter110 = LogicLimit110.filter_; var output110 = LogicLimit110.output_; PhysicProfiling PhysicProfiling111 = stmt.physicPlan_.LocateNode("111") as PhysicProfiling; LogicAgg LogicAgg111 = PhysicProfiling111.logic_ as LogicAgg; var filter111 = LogicAgg111.filter_; var output111 = LogicAgg111.output_; PhysicHashAgg PhysicHashAgg112 = stmt.physicPlan_.LocateNode("112") as PhysicHashAgg; LogicAgg LogicAgg112 = PhysicHashAgg112.logic_ as LogicAgg; var filter112 = LogicAgg112.filter_; var output112 = LogicAgg112.output_; PhysicProfiling PhysicProfiling113 = stmt.physicPlan_.LocateNode("113") as PhysicProfiling; LogicJoin LogicJoin113 = PhysicProfiling113.logic_ as LogicJoin; var filter113 = LogicJoin113.filter_; var output113 = LogicJoin113.output_; PhysicHashJoin PhysicHashJoin114 = stmt.physicPlan_.LocateNode("114") as PhysicHashJoin; LogicJoin LogicJoin114 = PhysicHashJoin114.logic_ as LogicJoin; var filter114 = LogicJoin114.filter_; var output114 = LogicJoin114.output_; PhysicProfiling PhysicProfiling115 = stmt.physicPlan_.LocateNode("115") as PhysicProfiling; LogicJoin LogicJoin115 = PhysicProfiling115.logic_ as LogicJoin; var filter115 = LogicJoin115.filter_; var output115 = LogicJoin115.output_; PhysicHashJoin PhysicHashJoin116 = stmt.physicPlan_.LocateNode("116") as PhysicHashJoin; LogicJoin LogicJoin116 = PhysicHashJoin116.logic_ as LogicJoin; var filter116 = LogicJoin116.filter_; var output116 = LogicJoin116.output_; PhysicProfiling PhysicProfiling117 = stmt.physicPlan_.LocateNode("117") as PhysicProfiling; LogicScanTable LogicScanTable117 = PhysicProfiling117.logic_ as LogicScanTable; var filter117 = LogicScanTable117.filter_; var output117 = LogicScanTable117.output_; PhysicScanTable PhysicScanTablea = stmt.physicPlan_.LocateNode("a") as PhysicScanTable; LogicScanTable LogicScanTablea = PhysicScanTablea.logic_ as LogicScanTable; var filtera = LogicScanTablea.filter_; var outputa = LogicScanTablea.output_; PhysicProfiling PhysicProfiling118 = stmt.physicPlan_.LocateNode("118") as PhysicProfiling; LogicScanTable LogicScanTable118 = PhysicProfiling118.logic_ as LogicScanTable; var filter118 = LogicScanTable118.filter_; var output118 = LogicScanTable118.output_; PhysicScanTable PhysicScanTablec = stmt.physicPlan_.LocateNode("c") as PhysicScanTable; LogicScanTable LogicScanTablec = PhysicScanTablec.logic_ as LogicScanTable; var filterc = LogicScanTablec.filter_; var outputc = LogicScanTablec.output_; var hm116 = new Dictionary <KeyList, List <TaggedRow> >(); PhysicProfiling PhysicProfiling119 = stmt.physicPlan_.LocateNode("119") as PhysicProfiling; LogicScanTable LogicScanTable119 = PhysicProfiling119.logic_ as LogicScanTable; var filter119 = LogicScanTable119.filter_; var output119 = LogicScanTable119.output_; PhysicScanTable PhysicScanTableb = stmt.physicPlan_.LocateNode("b") as PhysicScanTable; LogicScanTable LogicScanTableb = PhysicScanTableb.logic_ as LogicScanTable; var filterb = LogicScanTableb.filter_; var outputb = LogicScanTableb.output_; var hm114 = new Dictionary <KeyList, List <TaggedRow> >(); var aggrcore112 = LogicAgg112.aggrFns_; var hm112 = new Dictionary <KeyList, Row>(); var nrows110 = 0; PhysicProfiling109.nloops_++; PhysicProfiling111.nloops_++; PhysicProfiling113.nloops_++; PhysicProfiling115.nloops_++; PhysicProfiling117.nloops_++; var heapa = (LogicScanTablea.tabref_).Table().heap_.GetEnumerator(); for (;;) { Row ra = null; if (context.stop_) { break; } if (heapa.MoveNext()) { ra = heapa.Current; } else { break; } { { // projection on PhysicScanTablea: Output: a.a1[0],a.a2[1] Row rproj = new Row(2); rproj[0] = ra[0]; rproj[1] = ra[1]; ra = rproj; } PhysicProfiling117.nrows_++; var r117 = ra; var keys116 = KeyList.ComputeKeys(context, LogicJoin116.leftKeys_, r117); if (hm116.TryGetValue(keys116, out List <TaggedRow> exist)) { exist.Add(new TaggedRow(r117)); } else { var rows = new List <TaggedRow>(); rows.Add(new TaggedRow(r117)); hm116.Add(keys116, rows); } } } if (hm116.Count == 0) { return; } PhysicProfiling118.nloops_++; var heapc = (LogicScanTablec.tabref_).Table().heap_.GetEnumerator(); for (;;) { Row rc = null; if (context.stop_) { break; } if (heapc.MoveNext()) { rc = heapc.Current; } else { break; } { { // projection on PhysicScanTablec: Output: c.c2[1] Row rproj = new Row(1); rproj[0] = rc[1]; rc = rproj; } PhysicProfiling118.nrows_++; var r118 = rc; if (context.stop_) { return; } Row fakel116 = new Row(2); Row r116 = new Row(fakel116, r118); var keys116 = KeyList.ComputeKeys(context, LogicJoin116.rightKeys_, r116); bool foundOneMatch116 = false; if (hm116.TryGetValue(keys116, out List <TaggedRow> exist116)) { foundOneMatch116 = true; foreach (var v116 in exist116) { r116 = new Row(v116.row_, r118); { // projection on PhysicHashJoin116: Output: a.a1[0],a.a2[1] Row rproj = new Row(2); rproj[0] = r116[0]; rproj[1] = r116[1]; r116 = rproj; } PhysicProfiling115.nrows_++; var r115 = r116; var keys114 = KeyList.ComputeKeys(context, LogicJoin114.leftKeys_, r115); if (hm114.TryGetValue(keys114, out List <TaggedRow> exist)) { exist.Add(new TaggedRow(r115)); } else { var rows = new List <TaggedRow>(); rows.Add(new TaggedRow(r115)); hm114.Add(keys114, rows); } } } else { // no match for antisemi } } } if (hm114.Count == 0) { return; } PhysicProfiling119.nloops_++; var heapb = (LogicScanTableb.tabref_).Table().heap_.GetEnumerator(); for (;;) { Row rb = null; if (context.stop_) { break; } if (heapb.MoveNext()) { rb = heapb.Current; } else { break; } { { // projection on PhysicScanTableb: Output: b.b1[0] Row rproj = new Row(1); rproj[0] = rb[0]; rb = rproj; } PhysicProfiling119.nrows_++; var r119 = rb; if (context.stop_) { return; } Row fakel114 = new Row(2); Row r114 = new Row(fakel114, r119); var keys114 = KeyList.ComputeKeys(context, LogicJoin114.rightKeys_, r114); bool foundOneMatch114 = false; if (hm114.TryGetValue(keys114, out List <TaggedRow> exist114)) { foundOneMatch114 = true; foreach (var v114 in exist114) { r114 = new Row(v114.row_, r119); { // projection on PhysicHashJoin114: Output: a.a1[0],a.a2[1] Row rproj = new Row(2); rproj[0] = r114[0]; rproj[1] = r114[1]; r114 = rproj; } PhysicProfiling113.nrows_++; var r113 = r114; var keys = KeyList.ComputeKeys(context, LogicAgg112.keys_, r113); if (hm112.TryGetValue(keys, out Row exist)) { for (int i = 0; i < 1; i++) { var old = exist[i]; exist[i] = aggrcore112[i].Accum(context, old, r113); } } else { hm112.Add(keys, PhysicHashAgg112.AggrCoreToRow(r113)); exist = hm112[keys]; for (int i = 0; i < 1; i++) { exist[i] = aggrcore112[i].Init(context, r113); } } } } else { // no match for antisemi } } } foreach (var v112 in hm112) { if (context.stop_) { break; } var keys112 = v112.Key; Row aggvals112 = v112.Value; for (int i = 0; i < 1; i++) { aggvals112[i] = aggrcore112[i].Finalize(context, aggvals112[i]); } var r112 = new Row(keys112, aggvals112); if (true || LogicAgg112.having_.Exec(context, r112) is true) { { // projection on PhysicHashAgg112: Output: {a.a2}[0]*2,{count(a.a1)}[1],repeat('a',{a.a2}[0]) Row rproj = new Row(3); rproj[0] = ((dynamic)r112[0] * (dynamic)2); rproj[1] = r112[1]; rproj[2] = ExprSearch.Locate("74").Exec(context, r112) /*repeat('a',{a.a2}[0])*/; r112 = rproj; } PhysicProfiling111.nrows_++; var r111 = r112; nrows110++; Debug.Assert(nrows110 <= 2); if (nrows110 == 2) { context.stop_ = true; } var r110 = r111; PhysicProfiling109.nrows_++; var r109 = r110; Row newr = new Row(3); newr[0] = r109[0]; newr[1] = r109[1]; newr[2] = r109[2]; PhysicCollect108.rows_.Add(newr); Console.WriteLine(newr); } } }
static void Main(string[] args) { Catalog.Init(); string sql = ""; //TestTpcds_LoadData(); if (false) { JOBench.CreateTables(); sql = File.ReadAllText("../../../jobench/10a.sql"); goto doit; } if (false) { Tpch.CreateTables(); Tpch.LoadTables("0001"); //Tpch.CreateIndexes(); Tpch.AnalyzeTables(); sql = File.ReadAllText("../../../tpch/q20.sql"); goto doit; } if (true) { Tpcds.CreateTables(); //Tpcds.LoadTables("tiny"); //Tpcds.AnalyzeTables(); // 1, 2,3,7,10, // long time: 4 bad plan // 6: distinct not supported, causing wrong result sql = File.ReadAllText("../../../tpcds/q7.sql"); goto doit; } doit: sql = "with cte as (select * from d) select * from cte where d1=1;"; sql = "with cte as (select * from a) select cte1.a1, cte2.a2 from cte cte1, cte cte2 where cte2.a3<3"; // ok sql = "with cte as (select * from a) select * from cte cte1, cte cte2 where cte1.a2=cte2.a3 and cte1.a1> 0 order by 1;"; sql = "select ab.a1, cd.c1 from (select * from a join b on a1=b1) ab , (select * from c join d on c1=d1) cd where ab.a1=cd.c1"; sql = "select * from (select avg(a2) from a join b on a1=b1) a (a1) join b on a1=b1;"; sql = "with cte as (select * from a join b on a1=b1 join c on a2=c2) select * from cte cte1, cte cte2;"; // ok sql = "with cte as (select count(*) from a join b on a1=b1) select * from cte cte1;"; // ok sql = "with cte as (select count(*) from a join b on a1=b1) select * from cte cte1, cte cte2;"; sql = "with cte as (select * from d where d1=1) select * from cte cte1, cte cte2;"; sql = "with cte as (select * from a where a1=1) select * from cte cte1, cte cte2;"; var stopWatch = new Stopwatch(); stopWatch.Start(); Console.WriteLine(sql); var a = RawParser.ParseSingleSqlStatement(sql); a.queryOpt_.profile_.enabled_ = true; a.queryOpt_.optimize_.enable_subquery_unnest_ = true; a.queryOpt_.optimize_.remove_from_ = false; a.queryOpt_.optimize_.use_memo_ = true; a.queryOpt_.optimize_.enable_cte_plan_ = false; a.queryOpt_.optimize_.use_codegen_ = false; //a.queryOpt_.optimize_.memo_disable_crossjoin = false; //a.queryOpt_.optimize_.use_joinorder_solver = true; // -- Semantic analysis: // - bind the query a.queryOpt_.optimize_.ValidateOptions(); a.Bind(null); // -- generate an initial plan ExplainOption.show_tablename_ = false; a.queryOpt_.explain_.show_output_ = false; a.queryOpt_.explain_.show_cost_ = a.queryOpt_.optimize_.use_memo_; var rawplan = a.CreatePlan(); Console.WriteLine("***************** raw plan *************"); Console.WriteLine(rawplan.Explain(0)); physic.PhysicNode phyplan = null; if (a.queryOpt_.optimize_.use_memo_) { Console.WriteLine("***************** optimized plan *************"); var optplan = a.SubstitutionOptimize(); Console.WriteLine(optplan.Explain(0, a.queryOpt_.explain_)); a.optimizer_.InitRootPlan(a); a.optimizer_.OptimizeRootPlan(a, null); Console.WriteLine(a.optimizer_.PrintMemo()); phyplan = a.optimizer_.CopyOutOptimalPlan(); Console.WriteLine(a.optimizer_.PrintMemo()); Console.WriteLine("***************** Memo plan *************"); Console.WriteLine(phyplan.Explain(0, a.queryOpt_.explain_)); } else { // -- optimize the plan Console.WriteLine("-- optimized plan --"); var optplan = a.SubstitutionOptimize(); Console.WriteLine(optplan.Explain(0, a.queryOpt_.explain_)); // -- physical plan Console.WriteLine("-- physical plan --"); phyplan = a.physicPlan_; Console.WriteLine(phyplan.Explain(0, a.queryOpt_.explain_)); } Console.WriteLine("-- profiling plan --"); var final = new PhysicCollect(phyplan); a.physicPlan_ = final; var context = new ExecContext(a.queryOpt_); final.ValidateThis(); if (a is SelectStmt select) { select.OpenSubQueries(context); } var code = final.Open(context); code += final.Exec(null); code += final.Close(); if (a.queryOpt_.optimize_.use_codegen_) { CodeWriter.WriteLine(code); Compiler.Run(Compiler.Compile(), a, context); } Console.WriteLine(phyplan.Explain(0, a.queryOpt_.explain_)); stopWatch.Stop(); Console.WriteLine("RunTime: " + stopWatch.Elapsed); Console.ReadKey(); }