<ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll Newtonsoft.Json Newtonsoft.Json.Converters Newtonsoft.Json.Linq Newtonsoft.Json.Schema Newtonsoft.Json.Serialization System System.Diagnostics System.Diagnostics.Tracing System.Dynamic System.IO.Compression System.Threading.Tasks #region *** Enumerations *** public enum QueryRegions { Production, Training, Oak, Dev } #endregion #region *** Options *** public static string crossDBQueryPath = @"D:\CrossDBQueries"; public static QueryRegions queryRegion = QueryRegions.Production; public static bool dumpSmcSql = false; public static bool dumpDBList = true; public static bool dumpQueries = false; public static string[] appVersions = { }; public static string[] serverExclusions = { @"paonsql19.sdt.local\instance1", @"paonsql17.sdt.local\instance1", @"p0555-sql-01.sdt.local\instance1", "P0000-sql-01.sdt.local", "P9900-SQL-03.sdt.local", "P9900-sql-05.sdt.local" }; public static string[] targetServers = { }; public static string[] targetDBs = { //"jazz prd Gillette Childrens 20150417.1" //"jazz prd Southern Illinois 20140408.1" //"jazz tst Southern Illinois 20190918.1" //"jazz dev master Prod" }; #endregion *** Options *** #region *** SMC Settings and queries *** public static string smcSql => @"SELECT di.ServerName, di.DatabaseGUID, di.DatabaseName, di.PhysicalName, di.OrgPin, di.AppVersion, di.Description FROM [dbo].[viewDatabaseInfo] di WHERE 1=1" + (queryRegion == QueryRegions.Dev ? @" AND di.PhysicalName like 'jazz%'" : $@" AND di.PhysicalName like 'jazz {(queryRegion != QueryRegions.Production ? "tst" : "prd")}%' AND di.ServerName like 'p%'") + (serverExclusions.Any() ? $@" AND di.ServerName not in ('{string.Join("', '", serverExclusions)}')" : "") + (targetServers.Any() ? $@" AND di.ServerName in ('{string.Join("', '", targetServers)}')" : "") + (targetDBs.Any() ? $@" AND di.PhysicalName IN ('{string.Join(", '", targetDBs)}') " : "") + (appVersions.Any() ? $@" AND di.AppVersion in ('{string.Join("', '", appVersions)}')" : ""); public static string smcServer { get; set; } public static string smcDB { get; set; } #endregion #region *** Program variables and settings *** public static int maxThreads = 8; public static int timeoutInMinutes = 2; public static IList crossDBQueryResults = new List(); public static IOrderedEnumerable databases => GetDatabases(); #endregion void Main() { databases .GroupBy(db => db.AppVersion, (grp, data) => data.Select(x => x.AppVersion).First()) .OrderByDescending(db => db) .Dump("AppVersions"); /* databases .Select(db => new { db.AppVersion, db.PhysicalName, OrgPin = $"'{db.OrgPin}'" }) .Where(db => db.AppVersion != "2019.43") .OrderByDescending(db => db.AppVersion) .ThenBy(db => db.OrgPin) .Dump("AppVersions"); */ // ExecuteCrossDBQueries() // //.Where(r => !r.Exceptions.Any() && (r.Results.First().Results.First().Count() != 2).Any()) // .OrderBy(dbqr => dbqr.Results.Any() ? 0 : 1) // .ThenBy(dbqr => dbqr.Database.DatabaseName).Dump(nameof(crossDBQueryResults)); } #region *** Other classes *** public class CrossDBQueryResult { public Database Database { get; set; } public List Results { get; set; } public List Exceptions { get; set; } public CrossDBQueryResult() { Results = new List(); Exceptions = new List(); } public CrossDBQueryResult(Database database, string name, IEnumerable enumerable) : this() { Database = database; Results.Add(new SqlResults(name, enumerable)); } public CrossDBQueryResult(Database database, Exception exception) : this() { Database = database; Exceptions.Add(exception.ExceptionMessage()); } object ToDump() => Exceptions.Any() ? (object)new { Database, Results, Exceptions } : new { Database, Results }; } public class SqlResults { public string Name { get; set; } public IEnumerable Results { get; set; } public SqlResults(string name, IEnumerable results) { Name = name; Results = results; } } public static class ExceptionExtension { public static string ExceptionMessage(this Exception exception) { return $@"{exception.Message}{(exception.InnerException != null ? $@" {"".PadLeft(40, '-')} {exception.InnerException.ExceptionMessage()}" : "")}"; } } public class Database { public string Server { get; set; } public Guid DatabaseGuid { get; set; } public string DatabaseName { get; set; } public string PhysicalName { get; set; } public string OrgPin { get; set; } public string AppVersion { get; set; } public string Description { get; set; } public Database() { } public Database(DataRow dr) { Server = dr.Field("ServerName"); DatabaseGuid = dr.Field("DatabaseGuid"); DatabaseName = dr.Field("DatabaseName"); PhysicalName = dr.Field("PhysicalName"); OrgPin = dr.Field("OrgPin"); AppVersion = dr.Field("AppVersion"); Description = dr.Field("Description"); } } public class ThreadWithState { private string connectionString => BuildConnectionString(_server, _databaseName); private Database _database; private string _server => _database?.Server ?? string.Empty; private string _databaseName => _database?.PhysicalName ?? string.Empty; private string sqlName; private IEnumerable _sqlQueries; public ThreadWithState(Database database, KeyValuePair> sqlqueries) { _database = database; sqlName = sqlqueries.Key; _sqlQueries = sqlqueries.Value; } public void ThreadProc() { var crossDB = crossDBQueryResults.FirstOrDefault(x => x.Database == _database); IEnumerable ThreadResults; foreach (var sqlQuery in _sqlQueries) { try { ThreadResults = SelectDynamic(connectionString, sqlQuery); var result = ThreadResults.First(); if (crossDB != null) { crossDB.Results.Add(new SqlResults(sqlName, ThreadResults)); } else { crossDB = new CrossDBQueryResult(_database, sqlName, ThreadResults); crossDBQueryResults.Add(crossDB); } } catch (Exception ex) { if (crossDB != null) { crossDB.Exceptions.Add(new Exception(sqlQuery, ex).ExceptionMessage()); } else { crossDBQueryResults.Add(new CrossDBQueryResult(_database, new Exception(sqlQuery, ex))); } } } } } #endregion #region *** Other methods here *** public static IOrderedEnumerable GetDatabases() { switch (queryRegion) { case QueryRegions.Production: smcServer = "ioak-sql-smc-01"; smcDB = "smc prod"; break; case QueryRegions.Training: smcServer = "ioak-sql-smc-01"; smcDB = "smc training"; break; case QueryRegions.Oak: smcServer = "ioak-sql-smc-01.sdt.local"; smcDB = "smc qa"; break; default: smcServer = "DDEN-SQL-SMC-01.sdt.local"; smcDB = "smc dev"; break; } if (dumpSmcSql) smcSql.Dump(nameof(smcSql)); IEnumerable dbInfos = new List(); var connStr = BuildConnectionString(smcServer, smcDB); using (var conn = new SqlConnection(connStr)) { conn.Open(); var command = new SqlCommand(smcSql, conn); command.CommandType = CommandType.Text; var table = new DataTable(); using (SqlDataReader reader = command.ExecuteReader()) { table.BeginLoadData(); table.Load(reader); table.EndLoadData(); conn.Close(); } dbInfos = table.AsEnumerable().Select(dr => new Database(dr)); } return dbInfos .OrderBy(d => d.Server).ThenBy(d => d.PhysicalName); } public Dictionary> GetUserQueries(string path = null) { var grp = 0; return Directory.GetFiles(path ?? Directory.GetCurrentDirectory(), "*.sql", SearchOption.TopDirectoryOnly) .ToDictionary(d => Path.GetFileNameWithoutExtension(d), f => File.ReadAllLines(f) .Select(r => { if (r.Equals("go", StringComparison.CurrentCultureIgnoreCase)) { r = ""; return new { grp = grp++, r }; } else { return new { grp, r }; } }).GroupBy(r => r.grp, (x, lines) => string.Join(" ", lines.Select(l => l.r).Where(l => !string.IsNullOrEmpty(l))))); } public static IEnumerable SelectDynamic(string connStr, string sql) { using (var conn = new SqlConnection(connStr)) { conn.Open(); var command = new SqlCommand(sql, conn); command.CommandType = CommandType.Text; command.CommandTimeout = (int)TimeSpan.FromMinutes(timeoutInMinutes).TotalSeconds; using (var reader = command.ExecuteReader()) { var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList(); foreach (IDataRecord record in reader as IEnumerable) { var expando = new ExpandoObject() as IDictionary; foreach (var name in names) expando[name] = record[name]; yield return expando; } } conn.Close(); } } public IList ExecuteCrossDBQueries() { if (dumpDBList) databases.Dump(nameof(databases)); var queries = GetUserQueries(crossDBQueryPath); if (dumpQueries) queries.Dump(nameof(queries)); RunCrossDBQuery(databases, queries); return crossDBQueryResults; } public void RunCrossDBQuery(IEnumerable databases, Dictionary> sqlList) { var stopWatch = DateTime.Now; var query = databases.AsParallel() .SelectMany(database => sqlList.Where(sql => sql.Value.Any()).AsParallel() .Select(sql => new ThreadWithState(database, sql))); foreach (var q in query) { q.ThreadProc(); } DateTime.Now.Subtract(stopWatch).TotalSeconds.Dump(nameof(stopWatch)); } public static string BuildConnectionString(string server, string database, string username = null, string password = null) { return username == null ? $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;" : $"data source={server};initial catalog='{database}';User ID={username};pwd={password}"; } #endregion