From 728659207e84e936cfed9ce5ee779fd2ec51266a Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Mon, 21 Jun 2021 16:08:10 +0300 Subject: [PATCH 01/19] Fix missing sys.dm_db_stats_properties during indexes scanning --- Properties/AssemblyInfo.cs | 4 +-- Server/Query.cs | 58 ++++++++++++++++++++++++-------------- Server/QueryEngine.cs | 4 ++- Server/ServerInfo.cs | 6 ++++ 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index d1351a7..d7d7d59 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -7,5 +7,5 @@ [assembly: AssemblyCopyright("Sergii Syrovatchenko")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("1.0.0.66")] -[assembly: AssemblyFileVersion("1.0.0.66")] +[assembly: AssemblyVersion("1.0.0.67")] +[assembly: AssemblyFileVersion("1.0.0.67")] diff --git a/Server/Query.cs b/Server/Query.cs index 62dd7bf..b823623 100644 --- a/Server/Query.cs +++ b/Server/Query.cs @@ -250,27 +250,7 @@ ObjectID INT NOT NULL , RowsSampled BIGINT , PRIMARY KEY (ObjectID, IndexID) ) - -INSERT INTO #Stats -SELECT s.[object_id] - , s.[stats_id] - , s.[no_recompute] - , p.[rows_sampled] * 100. / NULLIF(p.[rows], 0) - , p.[rows_sampled] -FROM ( - SELECT DISTINCT s.[object_id] - , s.[stats_id] - , s.[no_recompute] - FROM sys.stats s WITH(NOLOCK) - WHERE EXISTS( - SELECT * - FROM #Indexes i - WHERE s.[object_id] = i.ObjectID - AND s.[stats_id] = i.IndexID - AND i.IndexType IN (1, 2) - ) -) s -CROSS APPLY sys.dm_db_stats_properties(s.[object_id], s.[stats_id]) p +{9} DECLARE @MINUTE INT SET @MINUTE = DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()) @@ -333,6 +313,42 @@ i.IndexType IN (5, 6) ) "; + public const string StatsLite = @" +INSERT INTO #Stats (ObjectID, IndexID, IsNoRecompute) +SELECT DISTINCT s.[object_id] + , s.[stats_id] + , s.[no_recompute] +FROM sys.stats s WITH(NOLOCK) +WHERE EXISTS( + SELECT * + FROM #Indexes i + WHERE s.[object_id] = i.ObjectID + AND s.[stats_id] = i.IndexID + AND i.IndexType IN (1, 2) + )"; + + public const string StatsFull = @" +INSERT INTO #Stats (ObjectID, IndexID, IsNoRecompute, StatsSampled, RowsSampled) +SELECT s.[object_id] + , s.[stats_id] + , s.[no_recompute] + , p.[rows_sampled] * 100. / NULLIF(p.[rows], 0) + , p.[rows_sampled] +FROM ( + SELECT DISTINCT s.[object_id] + , s.[stats_id] + , s.[no_recompute] + FROM sys.stats s WITH(NOLOCK) + WHERE EXISTS( + SELECT * + FROM #Indexes i + WHERE s.[object_id] = i.ObjectID + AND s.[stats_id] = i.IndexID + AND i.IndexType IN (1, 2) + ) +) s +CROSS APPLY sys.dm_db_stats_properties(s.[object_id], s.[stats_id]) p"; + public const string MissingIndex = @" SET NOCOUNT ON diff --git a/Server/QueryEngine.cs b/Server/QueryEngine.cs index a91a84d..3109da3 100644 --- a/Server/QueryEngine.cs +++ b/Server/QueryEngine.cs @@ -150,9 +150,11 @@ public static List GetIndexes(SqlConnection connection) { string ignorePermissions = Settings.Options.IgnorePermissions ? "" : "AND PERMISSIONS(i.[object_id]) & 2 = 2 "; string ignoreHeapWithCompression = Settings.Options.IgnoreHeapWithCompression ? "AND (i.[type] != 0 OR (i.[type] = 0 AND p.DataCompression = 0)) " : ""; + string statsInfo = Settings.ServerInfo.IsFullStats ? Query.StatsFull : Query.StatsLite; + string query = string.Format(Query.PreDescribeIndexes, string.Join(", ", it), excludeList, indexQuery, lob, - indexStats, ignoreReadOnlyFL, ignorePermissions, includeList, ignoreHeapWithCompression); + indexStats, ignoreReadOnlyFL, ignorePermissions, includeList, ignoreHeapWithCompression, statsInfo); SqlCommand cmd = new SqlCommand(query, connection) { CommandTimeout = Settings.Options.CommandTimeout }; diff --git a/Server/ServerInfo.cs b/Server/ServerInfo.cs index bcf653d..627b934 100644 --- a/Server/ServerInfo.cs +++ b/Server/ServerInfo.cs @@ -28,6 +28,12 @@ public override string ToString() => $"SQL Server {ProductVersion} " + || (MajorVersion == ServerVersion.Sql2016 && PatchVersion >= 4001) || MajorVersion >= ServerVersion.Sql2017; + // https://www.sqlskills.com/blogs/erin/new-statistics-dmf-in-sql-server-2008r2-sp2/ + public bool IsFullStats => IsAzure + || (MajorVersion >= ServerVersion.Sql2008 && MinorVersion == 50 && PatchVersion >= 4000) + || (MajorVersion == ServerVersion.Sql2012 && PatchVersion >= 3000) + || MajorVersion >= ServerVersion.Sql2014; + public bool IsOnlineRebuildAvailable => IsAzure || (MajorVersion >= ServerVersion.Sql2008 && IsMaxEdititon); From 15ddffbf57ac091234153f223455983acb118039 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 27 Jun 2021 16:26:52 +0300 Subject: [PATCH 02/19] Fix issue with empty list of databases if any database metadata is corrupted --- Forms/DatabaseBox.cs | 13 +++++++-- Properties/Resources.Designer.cs | 9 ++++++ Properties/Resources.resx | 3 ++ Server/Database.cs | 9 ++++-- Server/Query.cs | 48 ++++++++++---------------------- Server/QueryEngine.cs | 46 +++++++++++++++++++----------- 6 files changed, 72 insertions(+), 56 deletions(-) diff --git a/Forms/DatabaseBox.cs b/Forms/DatabaseBox.cs index dd08e3f..d610bb5 100644 --- a/Forms/DatabaseBox.cs +++ b/Forms/DatabaseBox.cs @@ -60,8 +60,17 @@ private void ScanDatabases(object sender, DoWorkEventArgs e) { try { connection.Open(); - _disks = QueryEngine.GetDiskInfo(connection); - _databases = QueryEngine.GetDatabases(connection); + try { _disks = QueryEngine.GetDiskInfo(connection); } + catch (Exception ex) { Output.Current.Add("Refresh disk info failed", ex.Message); } + + try { _databases = QueryEngine.GetDatabases(connection); } + catch (Exception ex) { Output.Current.Add("Refresh databases failed", ex.Message); } + + if (_databases.Count > 0 && !Settings.ServerInfo.IsAzure) { + try { QueryEngine.RefreshDatabaseSize(connection, _databases); } + catch (Exception ex) { Output.Current.Add("Refresh database sizes failed", ex.Message); } + } + } catch (Exception ex) { Output.Current.Add("Refresh failed", ex.Message); diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index 612e636..2fc808f 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -78,6 +78,15 @@ internal static string DatabaseBoxTitle { } } + /// + /// Looks up a localized string similar to DatabaseId. + /// + internal static string DatabaseId { + get { + return ResourceManager.GetString("DatabaseId", resourceCulture); + } + } + /// /// Looks up a localized string similar to DatabaseName. /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index d0ce254..706e626 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -394,4 +394,7 @@ ..\Images\icon_hide.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + DatabaseId + \ No newline at end of file diff --git a/Server/Database.cs b/Server/Database.cs index 10e3e1b..4db4260 100644 --- a/Server/Database.cs +++ b/Server/Database.cs @@ -4,15 +4,18 @@ namespace SQLIndexManager { public class Database { + public int DatabaseId { get; set; } public string DatabaseName { get; set; } public string RecoveryModel { get; set; } public string LogReuseWait { get; set; } public DateTime CreateDate { get; set; } - public long TotalSize { get; set; } + public long TotalSize => DataUsedSize + LogSize; public long DataSize { get; set; } - public long DataFreeSize { get; set; } + public long DataUsedSize { get; set; } + public long DataFreeSize => DataSize - DataUsedSize; public long LogSize { get; set; } - public long LogFreeSize { get; set; } + public long LogUsedSize { get; set; } + public long LogFreeSize => LogSize - LogUsedSize; } diff --git a/Server/Query.cs b/Server/Query.cs index b823623..988d4c8 100644 --- a/Server/Query.cs +++ b/Server/Query.cs @@ -598,7 +598,7 @@ FROM sys.dm_db_index_physical_stats(@DBID, @ObjectID, @IndexID, @PartitionNumber , IsSysAdmin = CAST(IS_SRVROLEMEMBER('sysadmin') AS BIT) "; - public const string DatabaseList = @" + public const string DatabaseSizeList = @" SET NOCOUNT ON SET ARITHABORT ON SET NUMERIC_ROUNDABORT OFF @@ -607,29 +607,21 @@ IF OBJECT_ID('tempdb.dbo.#Databases') IS NOT NULL DROP TABLE #Databases CREATE TABLE #Databases ( - DatabaseID INT - , DatabaseName NVARCHAR(500) - , RecoveryModel NVARCHAR(500) - , LogReuseWait NVARCHAR(500) - , HasDBAccess BIT - , CreateDate DATETIME + DatabaseName NVARCHAR(500) + , HasDBAccess BIT ) INSERT INTO #Databases -SELECT DatabaseID = [database_id] - , DatabaseName = [name] - , RecoveryModel = [recovery_model_desc] - , LogReuseWait = [log_reuse_wait_desc] - , HasDBAccess = ISNULL(HAS_DBACCESS([name]), 1) - , CreateDate = DATEADD(MINUTE, -DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), [create_date]) +SELECT DatabaseName = [name] + , HasDBAccess = ISNULL(HAS_DBACCESS([name]), 1) FROM sys.databases WITH(NOLOCK) WHERE [state] = 0 AND [user_access] = 0 -IF OBJECT_ID('tempdb.dbo.#UsedSpace') IS NOT NULL - DROP TABLE #UsedSpace +IF OBJECT_ID('tempdb.dbo.#DatabaseSize') IS NOT NULL + DROP TABLE #DatabaseSize -CREATE TABLE #UsedSpace ( +CREATE TABLE #DatabaseSize ( DatabaseID INT , DataSize BIGINT , LogSize BIGINT @@ -641,7 +633,7 @@ DECLARE @SQL NVARCHAR(MAX) SET @SQL = ( SELECT ' USE [' + REPLACE(REPLACE(DatabaseName, ']', ']]'), '[', '[[') + '] - INSERT INTO #UsedSpace + INSERT INTO #DatabaseSize SELECT DB_ID() , SUM(CASE WHEN [type] = 0 THEN [size] END) , SUM(CASE WHEN [type] = 1 THEN [size] END) @@ -661,25 +653,13 @@ FOR XML PATH(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)') EXEC sys.sp_executesql @SQL -SELECT t.DatabaseName - , u.DataSize - , u.DataUsedSize - , u.LogSize - , u.LogUsedSize - , t.RecoveryModel - , t.LogReuseWait - , t.CreateDate -FROM #Databases t -LEFT JOIN #UsedSpace u ON u.DatabaseID = t.DatabaseID -WHERE t.HasDBAccess = 1 +SELECT * +FROM #DatabaseSize "; - public const string DatabaseListAzure = @" -SELECT DatabaseName = [name] - , DataSize = CAST(NULL AS BIGINT) - , DataUsedSize = CAST(NULL AS BIGINT) - , LogSize = CAST(NULL AS BIGINT) - , LogUsedSize = CAST(NULL AS BIGINT) + public const string DatabaseList = @" +SELECT DatabaseId = [database_id] + , DatabaseName = [name] , RecoveryModel = [recovery_model_desc] , LogReuseWait = [log_reuse_wait_desc] , CreateDate = DATEADD(MINUTE, -DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), [create_date]) diff --git a/Server/QueryEngine.cs b/Server/QueryEngine.cs index 3109da3..980d110 100644 --- a/Server/QueryEngine.cs +++ b/Server/QueryEngine.cs @@ -10,30 +10,21 @@ namespace SQLIndexManager { public static class QueryEngine { public static List GetDatabases(SqlConnection connection) { - string query = !Settings.ServerInfo.IsAzure ? Query.DatabaseList : Query.DatabaseListAzure; - - SqlCommand cmd = new SqlCommand(query, connection) { CommandTimeout = Settings.Options.CommandTimeout }; + SqlCommand cmd = new SqlCommand(Query.DatabaseList, connection) { CommandTimeout = Settings.Options.CommandTimeout }; SqlDataAdapter adapter = new SqlDataAdapter(cmd); DataSet data = new DataSet(); adapter.Fill(data); List dbs = new List(); - foreach (DataRow _ in data.Tables[0].Rows) { - long dataSize = _.Field(Resources.DataSize) ?? 0; - long logSize = _.Field(Resources.LogSize) ?? 0; - + foreach (DataRow r in data.Tables[0].Rows) { dbs.Add( new Database { - DatabaseName = _.Field(Resources.DatabaseName), - RecoveryModel = _.Field(Resources.RecoveryModel), - LogReuseWait = _.Field(Resources.LogReuseWait), - CreateDate = _.Field(Resources.CreateDate), - TotalSize = dataSize + logSize, - DataSize = dataSize, - DataFreeSize = dataSize - (_.Field(Resources.DataUsedSize) ?? 0), - LogSize = logSize, - LogFreeSize = logSize - (_.Field(Resources.LogUsedSize) ?? 0) + DatabaseId = r.Field(Resources.DatabaseId), + DatabaseName = r.Field(Resources.DatabaseName), + RecoveryModel = r.Field(Resources.RecoveryModel), + LogReuseWait = r.Field(Resources.LogReuseWait), + CreateDate = r.Field(Resources.CreateDate) } ); } @@ -41,6 +32,28 @@ public static List GetDatabases(SqlConnection connection) { return dbs; } + public static List RefreshDatabaseSize(SqlConnection connection, List dbs) { + SqlCommand cmd = new SqlCommand(Query.DatabaseSizeList, connection) { CommandTimeout = Settings.Options.CommandTimeout }; + + SqlDataAdapter adapter = new SqlDataAdapter(cmd); + DataSet data = new DataSet(); + adapter.Fill(data); + + foreach (DataRow r in data.Tables[0].Rows) { + int databaseId = r.Field(Resources.DatabaseId); + Database db = dbs.FirstOrDefault(_ => _.DatabaseId == databaseId); + + if (db != null) { + db.DataSize = r.Field(Resources.DataSize) ?? 0; + db.DataUsedSize = r.Field(Resources.DataUsedSize) ?? 0; + db.LogSize = r.Field(Resources.LogSize) ?? 0; + db.LogUsedSize = r.Field(Resources.LogUsedSize) ?? 0; + } + } + + return dbs; + } + public static List GetDiskInfo(SqlConnection connection) { List di = new List(); @@ -51,7 +64,6 @@ public static List GetDiskInfo(SqlConnection connection) { DataSet data = new DataSet(); adapter.Fill(data); - foreach (DataRow _ in data.Tables[0].Rows) { di.Add( new DiskInfo { From fc0550ec1e362fa2867d7989105aa35baf8a6f73 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 27 Jun 2021 18:33:11 +0300 Subject: [PATCH 03/19] Improvements in grid context menu --- Forms/ActionBox.Designer.cs | 93 ------------------------ Forms/ActionBox.cs | 79 -------------------- Forms/ActionBox.resx | 120 ------------------------------- Forms/MainBox.Designer.cs | 2 +- Forms/MainBox.cs | 41 +++++++++-- Images/icon_delete.png | Bin 0 -> 307 bytes Images/icon_skip.png | Bin 0 -> 317 bytes Images/icon_update_stats.png | Bin 0 -> 380 bytes Properties/Resources.Designer.cs | 34 ++++++++- Properties/Resources.resx | 11 ++- SQLIndexManager.csproj | 12 +--- Server/QueryEngine.cs | 8 +-- 12 files changed, 85 insertions(+), 315 deletions(-) delete mode 100644 Forms/ActionBox.Designer.cs delete mode 100644 Forms/ActionBox.cs delete mode 100644 Forms/ActionBox.resx create mode 100644 Images/icon_delete.png create mode 100644 Images/icon_skip.png create mode 100644 Images/icon_update_stats.png diff --git a/Forms/ActionBox.Designer.cs b/Forms/ActionBox.Designer.cs deleted file mode 100644 index 5c07905..0000000 --- a/Forms/ActionBox.Designer.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace SQLIndexManager { - partial class ActionBox { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) { - if (disposing && (components != null)) { - components.Dispose(); - } - - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() { - this.buttonCancel = new DevExpress.XtraEditors.SimpleButton(); - this.buttonOK = new DevExpress.XtraEditors.SimpleButton(); - this.boxFixAction = new DevExpress.XtraEditors.ComboBoxEdit(); - ((System.ComponentModel.ISupportInitialize)(this.boxFixAction.Properties)).BeginInit(); - this.SuspendLayout(); - // - // buttonCancel - // - this.buttonCancel.AllowFocus = false; - this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(200, 40); - this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(75, 23); - this.buttonCancel.TabIndex = 7; - this.buttonCancel.Text = "Cancel"; - // - // buttonOK - // - this.buttonOK.AllowFocus = false; - this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.buttonOK.Location = new System.Drawing.Point(119, 40); - this.buttonOK.Name = "buttonOK"; - this.buttonOK.Size = new System.Drawing.Size(75, 23); - this.buttonOK.TabIndex = 6; - this.buttonOK.Text = "OK"; - // - // boxFixAction - // - this.boxFixAction.Location = new System.Drawing.Point(12, 10); - this.boxFixAction.Name = "boxFixAction"; - this.boxFixAction.Properties.AllowFocused = false; - this.boxFixAction.Properties.AutoComplete = false; - this.boxFixAction.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { - new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); - this.boxFixAction.Properties.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.DisableTextEditor; - this.boxFixAction.Size = new System.Drawing.Size(263, 20); - this.boxFixAction.TabIndex = 2; - // - // ActionBox - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(284, 75); - this.Controls.Add(this.boxFixAction); - this.Controls.Add(this.buttonCancel); - this.Controls.Add(this.buttonOK); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; - this.LookAndFeel.SkinName = "Office 2016 Dark"; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "ActionBox"; - this.ShowIcon = false; - this.ShowInTaskbar = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Change Fix Action"; - ((System.ComponentModel.ISupportInitialize)(this.boxFixAction.Properties)).EndInit(); - this.ResumeLayout(false); - - } - - #endregion - - private DevExpress.XtraEditors.SimpleButton buttonCancel; - private DevExpress.XtraEditors.SimpleButton buttonOK; - private DevExpress.XtraEditors.ComboBoxEdit boxFixAction; - } -} \ No newline at end of file diff --git a/Forms/ActionBox.cs b/Forms/ActionBox.cs deleted file mode 100644 index 958b0e9..0000000 --- a/Forms/ActionBox.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Collections.Generic; -using System.Windows.Forms; -using DevExpress.XtraEditors; - -namespace SQLIndexManager { - - public partial class ActionBox : XtraForm { - - public ActionBox() { - InitializeComponent(); - - List indexOps = new List { IndexOp.REBUILD, IndexOp.REORGANIZE }; - if (Settings.ServerInfo.IsCompressionAvailable) { - indexOps.AddRange(new List { - IndexOp.REBUILD_ROW, - IndexOp.REBUILD_PAGE, - IndexOp.REBUILD_NONE - } - ); - } - - if (Settings.ServerInfo.IsColumnstoreAvailable) { - indexOps.AddRange(new List { - IndexOp.REBUILD_COLUMNSTORE, - IndexOp.REBUILD_COLUMNSTORE_ARCHIVE - } - ); - - if (Settings.ServerInfo.MajorVersion >= ServerVersion.Sql2016) { - indexOps.Add(IndexOp.CREATE_COLUMNSTORE_INDEX); - } - } - - if (Settings.ServerInfo.IsOnlineRebuildAvailable) { - indexOps.Add(IndexOp.REBUILD_ONLINE); - } - - indexOps.AddRange(new List { - IndexOp.UPDATE_STATISTICS_SAMPLE, - IndexOp.UPDATE_STATISTICS_RESAMPLE, - IndexOp.UPDATE_STATISTICS_FULL, - IndexOp.DISABLE_INDEX, - IndexOp.DROP_TABLE, - IndexOp.SKIP - } - ); - - foreach (IndexOp op in indexOps) { - boxFixAction.Properties.Items.Add(op.Description()); - } - - boxFixAction.SelectedIndex = 0; - } - - public IndexOp GetFixAction() { - return Utils.GetValueFromDescription((string)boxFixAction.EditValue); - } - - #region Override Methods - - protected override bool ProcessDialogKey(Keys keyData) { - if (keyData == Keys.Escape) { - DialogResult = DialogResult.Cancel; - return true; - } - - if (keyData == Keys.Enter && buttonOK.Enabled) { - DialogResult = DialogResult.OK; - return true; - } - - return base.ProcessDialogKey(keyData); - } - - #endregion - - } - -} diff --git a/Forms/ActionBox.resx b/Forms/ActionBox.resx deleted file mode 100644 index 1af7de1..0000000 --- a/Forms/ActionBox.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Forms/MainBox.Designer.cs b/Forms/MainBox.Designer.cs index 6f92bb7..3332aaa 100644 --- a/Forms/MainBox.Designer.cs +++ b/Forms/MainBox.Designer.cs @@ -1490,7 +1490,7 @@ private void InitializeComponent() { // this.buttonSaveFix.Caption = "Save Fix Script"; this.buttonSaveFix.Id = 23; - this.buttonSaveFix.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IiconSaveFix; + this.buttonSaveFix.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconSaveFix; this.buttonSaveFix.Name = "buttonSaveFix"; this.buttonSaveFix.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ButtonSaveFixClick); // diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index 3a782e7..283119c 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -730,7 +730,38 @@ private void GridPopupMenuShowing(object sender, PopupMenuShowingEventArgs e) { return; if (view.OptionsBehavior.Editable) { - e.Menu.Items.Add(new DXMenuItem("Change Fix Action", ChangeFixAction, Resources.IconReplace)); + DXSubMenuItem ci = new DXSubMenuItem("Change Fix Action"); + ci.ImageOptions.Image = Resources.IconReplace; + e.Menu.Items.Add(ci); + + ci.Items.Add(new DXMenuItem(IndexOp.REBUILD.Description(), ChangeFixAction, Resources.IconIndexes)); + ci.Items.Add(new DXMenuItem(IndexOp.REORGANIZE.Description(), ChangeFixAction, Resources.IconIndexes)); + + if (Settings.ServerInfo.IsCompressionAvailable) { + ci.Items.Add(new DXMenuItem(IndexOp.REBUILD_ROW.Description(), ChangeFixAction, Resources.IconIndexes) { BeginGroup = true }); + ci.Items.Add(new DXMenuItem(IndexOp.REBUILD_PAGE.Description(), ChangeFixAction, Resources.IconIndexes)); + ci.Items.Add(new DXMenuItem(IndexOp.REBUILD_NONE.Description(), ChangeFixAction, Resources.IconIndexes)); + } + + if (Settings.ServerInfo.IsOnlineRebuildAvailable) { + ci.Items.Add(new DXMenuItem(IndexOp.REBUILD_ONLINE.Description(), ChangeFixAction, Resources.IconIndexes)); + } + + if (Settings.ServerInfo.IsColumnstoreAvailable) { + ci.Items.Add(new DXMenuItem(IndexOp.REBUILD_COLUMNSTORE.Description(), ChangeFixAction, Resources.IconIndexes) { BeginGroup = true }); + ci.Items.Add(new DXMenuItem(IndexOp.REBUILD_COLUMNSTORE_ARCHIVE.Description(), ChangeFixAction, Resources.IconIndexes)); + + if (Settings.ServerInfo.MajorVersion >= ServerVersion.Sql2016) { + ci.Items.Add(new DXMenuItem(IndexOp.CREATE_COLUMNSTORE_INDEX.Description(), ChangeFixAction, Resources.IconReplace)); + } + } + + ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_SAMPLE.Description(), ChangeFixAction, Resources.IconUpdateStats) { BeginGroup = true }); + ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_RESAMPLE.Description(), ChangeFixAction, Resources.IconUpdateStats)); + ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_FULL.Description(), ChangeFixAction, Resources.IconUpdateStats)); + ci.Items.Add(new DXMenuItem(IndexOp.DISABLE_INDEX.Description(), ChangeFixAction, Resources.IconHide) { BeginGroup = true }); + ci.Items.Add(new DXMenuItem(IndexOp.DROP_TABLE.Description(), ChangeFixAction, Resources.IconDelete)); + ci.Items.Add(new DXMenuItem(IndexOp.SKIP.Description(), ChangeFixAction, Resources.IconSkip) { BeginGroup = true }); } e.Menu.Items.Add(new DXMenuItem("Copy Fix Script", CopyFixScript, Resources.IconCopyFix)); @@ -813,11 +844,9 @@ private void HideCellValue(object sender, EventArgs e) { } private void ChangeFixAction(object sender, EventArgs e) { - using (ActionBox form = new ActionBox()) { - if (form.ShowDialog(this) == DialogResult.OK) { - UpdateFixAction(form.GetFixAction()); - } - } + DXMenuItem mi = (DXMenuItem)sender; + IndexOp op = Utils.GetValueFromDescription(mi.Caption); + UpdateFixAction(op); } private void UpdateFixAction(IndexOp op) { diff --git a/Images/icon_delete.png b/Images/icon_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..a7864138f68658a394a3b9a8e437d8f51b262ab7 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;%C9V-A z!TD(=<%vb942~)JNvR5+xryniL8*x;m4zo$ZGehoK#D>#OL9^f{PIgutzA-cQh`)Z zYHofRkjgJl3%vaosBW&Oi(`m||I$ep1)B|coULcs|9H!{_qCGkvPbK)OQg+>%$9r0 zc--n|cl0>KlDF!Y_(}_Bt#cPRzL#F++{L<{@mo`ofX;#StPv5MqCG_-3=hL!HVPbO zeOf2|!$w?l#eC^r?i{9FYzBuV6eJRrnZC*$ar=1LD5q)j`VSh*;yAaQmVe1RdG>Lx utUD3y%%09ZvITs)yoMqhCdytH`^nV5urA%)Uh5^$p$wj`elF{r5}E+bLTh*c literal 0 HcmV?d00001 diff --git a/Images/icon_skip.png b/Images/icon_skip.png new file mode 100644 index 0000000000000000000000000000000000000000..2af56fbc22fab82f1b1cbb81798bdeb0f7f8274c GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;%C9V-A z!TD(=<%vb942~)JNvR5+xryniL8*x;m4zo$ZGeizK#D>#OL9^ff>KlRtsRSs^2@DV zQ!-1eUj(jS15~lr)5S5w!hh+djl72(cv>HxX%sPJ5p_=C%~I=N5x(d+-B9CYW_CA!seapk!lvI6;%C9V-A z!TD(=<%vb942~)JNvR5+xryniL8*x;m4zo$ZGeiDL5e~$OL9^fob&U_Qj1EggHj7p z6HBZei;D8gtz9dUGZORCQ_GYyE&-L__jGX#vGDIbw~@CgK;T#*Hy2w0r@FyG$r*?G z7=1K0Ca}6MC}farl+CztU{cGYpZ1^6$?Q>%`os0^-S3Ls0*CykzY_~kx~aya;$+b{mt9G5j7lr`&3`gJuaJdvg%!7`+x4;=0CKT VKK;UaHyY?w22WQ%mvv4FO#prGkk + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap IconDelete { + get { + object obj = ResourceManager.GetObject("IconDelete", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -483,6 +493,16 @@ internal static System.Drawing.Bitmap IconSavedSpace { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap IconSaveFix { + get { + object obj = ResourceManager.GetObject("IconSaveFix", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -493,6 +513,16 @@ internal static System.Drawing.Bitmap IconScan { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap IconSkip { + get { + object obj = ResourceManager.GetObject("IconSkip", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -506,9 +536,9 @@ internal static System.Drawing.Bitmap IconStop { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - internal static System.Drawing.Bitmap IiconSaveFix { + internal static System.Drawing.Bitmap IconUpdateStats { get { - object obj = ResourceManager.GetObject("IiconSaveFix", resourceCulture); + object obj = ResourceManager.GetObject("IconUpdateStats", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } diff --git a/Properties/Resources.resx b/Properties/Resources.resx index 706e626..8359c00 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -349,7 +349,7 @@ master - + ..\Images\icon_save_fix.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -397,4 +397,13 @@ DatabaseId + + ..\Images\icon_delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Images\icon_skip.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Images\icon_update_stats.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/SQLIndexManager.csproj b/SQLIndexManager.csproj index 0af9426..a365ba3 100644 --- a/SQLIndexManager.csproj +++ b/SQLIndexManager.csproj @@ -92,12 +92,6 @@ - - Form - - - ActionBox.cs - Form @@ -170,9 +164,6 @@ - - ActionBox.cs - ErrorBox.cs @@ -201,6 +192,8 @@ + + @@ -225,6 +218,7 @@ + diff --git a/Server/QueryEngine.cs b/Server/QueryEngine.cs index 980d110..6115b06 100644 --- a/Server/QueryEngine.cs +++ b/Server/QueryEngine.cs @@ -44,10 +44,10 @@ public static List RefreshDatabaseSize(SqlConnection connection, List< Database db = dbs.FirstOrDefault(_ => _.DatabaseId == databaseId); if (db != null) { - db.DataSize = r.Field(Resources.DataSize) ?? 0; - db.DataUsedSize = r.Field(Resources.DataUsedSize) ?? 0; - db.LogSize = r.Field(Resources.LogSize) ?? 0; - db.LogUsedSize = r.Field(Resources.LogUsedSize) ?? 0; + db.DataSize = r.Field(Resources.DataSize) ?? 0; + db.DataUsedSize = r.Field(Resources.DataUsedSize) ?? 0; + db.LogSize = r.Field(Resources.LogSize) ?? 0; + db.LogUsedSize = r.Field(Resources.LogUsedSize) ?? 0; } } From cde9e430202e8b5e39ae5f0b7b93f4051cc9f0d6 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 27 Jun 2021 19:04:15 +0300 Subject: [PATCH 04/19] Added possibility to truncate tables --- Forms/MainBox.cs | 13 ++++++++++--- Images/icon_clear.png | Bin 0 -> 299 bytes Properties/Resources.Designer.cs | 19 +++++++++++++++++++ Properties/Resources.resx | 6 ++++++ SQLIndexManager.csproj | 1 + Server/Index.cs | 5 +++++ Server/Query.cs | 1 + Server/QueryEngine.cs | 3 ++- Types/IndexOp.cs | 5 ++++- 9 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 Images/icon_clear.png diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index 283119c..ddddb4c 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -638,6 +638,10 @@ private List GetIndexOperations(Index ix) { } } + if (ix.IsTable) { + i.Add(IndexOp.TRUNCATE_TABLE); + } + i.Add(IndexOp.SKIP); return i; @@ -756,11 +760,14 @@ private void GridPopupMenuShowing(object sender, PopupMenuShowingEventArgs e) { } } - ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_SAMPLE.Description(), ChangeFixAction, Resources.IconUpdateStats) { BeginGroup = true }); + ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_FULL.Description(), ChangeFixAction, Resources.IconUpdateStats) { BeginGroup = true }); ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_RESAMPLE.Description(), ChangeFixAction, Resources.IconUpdateStats)); - ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_FULL.Description(), ChangeFixAction, Resources.IconUpdateStats)); - ci.Items.Add(new DXMenuItem(IndexOp.DISABLE_INDEX.Description(), ChangeFixAction, Resources.IconHide) { BeginGroup = true }); + ci.Items.Add(new DXMenuItem(IndexOp.UPDATE_STATISTICS_SAMPLE.Description(), ChangeFixAction, Resources.IconUpdateStats)); + + ci.Items.Add(new DXMenuItem(IndexOp.TRUNCATE_TABLE.Description(), ChangeFixAction, Resources.IconClear) { BeginGroup = true }); + ci.Items.Add(new DXMenuItem(IndexOp.DISABLE_INDEX.Description(), ChangeFixAction, Resources.IconHide)); ci.Items.Add(new DXMenuItem(IndexOp.DROP_TABLE.Description(), ChangeFixAction, Resources.IconDelete)); + ci.Items.Add(new DXMenuItem(IndexOp.SKIP.Description(), ChangeFixAction, Resources.IconSkip) { BeginGroup = true }); } diff --git a/Images/icon_clear.png b/Images/icon_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..213b4d21ef80fdb923fb41fd43af9a95bff2129a GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;%C9V-A z!TD(=<%vb942~)JNvR5+xryniL8*x;m4zo$ZGehYL5e~$OL9^foO4nWi>zIX5{px< zgHm(z%TleK5{rthgEEtn^7E|Q8=8xO8hSik978Ppmrl6N+n^x8^7f?IpQT*Z8@0SQ z&YrAVUU8s_&0cL^nc6{DmpaGzxZlq>1p^D>bGq4?m5-h_3F=^Dvs#m?>@FqwqM>tM z!`n4;4%9`l={U5@-cp_r*#BI;?Qx89)9Si}CiRmCm?rdY_n5}W-J{eSBcCXuneu@7 nZbz?MM1$Ka!{&W|`gF`!Y-~C(r + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap IconClear { + get { + object obj = ResourceManager.GetObject("IconClear", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -678,6 +688,15 @@ internal static string IsSysAdmin { } } + /// + /// Looks up a localized string similar to IsTable. + /// + internal static string IsTable { + get { + return ResourceManager.GetString("IsTable", resourceCulture); + } + } + /// /// Looks up a localized string similar to IsUnique. /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index 8359c00..f84012a 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -406,4 +406,10 @@ ..\Images\icon_update_stats.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\icon_clear.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + IsTable + \ No newline at end of file diff --git a/SQLIndexManager.csproj b/SQLIndexManager.csproj index a365ba3..e07f94a 100644 --- a/SQLIndexManager.csproj +++ b/SQLIndexManager.csproj @@ -219,6 +219,7 @@ + diff --git a/Server/Index.cs b/Server/Index.cs index 752652c..b64e379 100644 --- a/Server/Index.cs +++ b/Server/Index.cs @@ -49,6 +49,7 @@ public class Index { public bool IsAllowReorganize { get; set; } public bool IsAllowOnlineRebuild { get; set; } public bool IsAllowCompression { get; set; } + public bool IsTable { get; set; } public bool IsColumnstore => (IndexType == IndexType.CLUSTERED_COLUMNSTORE || IndexType == IndexType.NONCLUSTERED_COLUMNSTORE); public string Error { get; set; } @@ -170,6 +171,10 @@ public string GetQuery() { sql = $"DROP TABLE {objectName};"; break; + case IndexOp.TRUNCATE_TABLE: + sql = $"TRUNCATE TABLE {objectName};"; + break; + case IndexOp.UPDATE_STATISTICS_SAMPLE: case IndexOp.UPDATE_STATISTICS_RESAMPLE: case IndexOp.UPDATE_STATISTICS_FULL: diff --git a/Server/Query.cs b/Server/Query.cs index 988d4c8..aa592ff 100644 --- a/Server/Query.cs +++ b/Server/Query.cs @@ -283,6 +283,7 @@ SELECT i.ObjectID , FileGroupName = fg.[name] , CreateDate = DATEADD(MINUTE, -@MINUTE, o.[create_date]) , ModifyDate = DATEADD(MINUTE, -@MINUTE, o.[modify_date]) + , IsTable = CAST(CASE WHEN o.[type] = 'U' THEN 1 ELSE 0 END AS BIT) , i.IsUnique , i.IsPK , i.FillFactorValue diff --git a/Server/QueryEngine.cs b/Server/QueryEngine.cs index 6115b06..91177c5 100644 --- a/Server/QueryEngine.cs +++ b/Server/QueryEngine.cs @@ -237,6 +237,7 @@ public static List GetIndexes(SqlConnection connection) { DataCompression = (DataCompression)_.Field(Resources.DataCompression), Fragmentation = _.Field(Resources.Fragmentation), PageSpaceUsed = _.Field(Resources.PageSpaceUsed), + IsTable = _.Field(Resources.IsTable), IsAllowReorganize = _.Field(Resources.IsAllowPageLocks) && indexType != IndexType.HEAP, IsAllowOnlineRebuild = isOnlineRebuild, IsAllowCompression = Settings.ServerInfo.IsCompressionAvailable && !_.Field(Resources.IsSparse), @@ -391,7 +392,7 @@ public static string FixIndex(SqlConnection connection, Index ix) { ix.IndexStats = DateTime.UtcNow; ix.Fragmentation = 0; } - else if (ix.FixType == IndexOp.DISABLE_INDEX || ix.FixType == IndexOp.DROP_INDEX || ix.FixType == IndexOp.DROP_TABLE) { + else if (ix.FixType == IndexOp.DISABLE_INDEX || ix.FixType == IndexOp.DROP_INDEX || ix.FixType == IndexOp.DROP_TABLE || ix.FixType == IndexOp.TRUNCATE_TABLE) { ix.PagesCountBefore = ix.PagesCount; ix.Fragmentation = 0; ix.PagesCount = 0; diff --git a/Types/IndexOp.cs b/Types/IndexOp.cs index 498880c..87c7813 100644 --- a/Types/IndexOp.cs +++ b/Types/IndexOp.cs @@ -61,7 +61,10 @@ public enum IndexOp { SKIP = 18, [Description("CREATE COLUMNSTORE INDEX")] - CREATE_COLUMNSTORE_INDEX = 19 + CREATE_COLUMNSTORE_INDEX = 19, + + [Description("TRUNCATE TABLE")] + TRUNCATE_TABLE = 20 } } From ef46aa3ad0a738440da924ecba3ef5b3cbe87ba1 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 27 Jun 2021 21:55:50 +0300 Subject: [PATCH 05/19] Improved auto-scroll + remove delay functionality --- Forms/DatabaseBox.Designer.cs | 154 +++++++++++++++---------------- Forms/MainBox.Designer.cs | 20 +++- Forms/MainBox.cs | 27 +++--- Forms/MainBox.resx | 21 +++++ Forms/SettingsBox.Designer.cs | 150 +++++------------------------- Forms/SettingsBox.cs | 5 - Forms/SettingsBox.resx | 6 -- Properties/Resources.Designer.cs | 10 -- Properties/Resources.resx | 3 - Settings/Options.cs | 14 --- 10 files changed, 151 insertions(+), 259 deletions(-) diff --git a/Forms/DatabaseBox.Designer.cs b/Forms/DatabaseBox.Designer.cs index 45d2fe2..a72b948 100644 --- a/Forms/DatabaseBox.Designer.cs +++ b/Forms/DatabaseBox.Designer.cs @@ -24,6 +24,7 @@ protected override void Dispose(bool disposing) { /// the contents of this method with the code editor. /// private void InitializeComponent() { + DevExpress.XtraLayout.LayoutControlGroup layoutControl; DevExpress.XtraGrid.GridFormatRule gridFormatRule1 = new DevExpress.XtraGrid.GridFormatRule(); DevExpress.XtraEditors.FormatConditionRuleDataBar formatConditionRuleDataBar1 = new DevExpress.XtraEditors.FormatConditionRuleDataBar(); DevExpress.XtraGrid.GridFormatRule gridFormatRule2 = new DevExpress.XtraGrid.GridFormatRule(); @@ -34,38 +35,37 @@ private void InitializeComponent() { DevExpress.XtraEditors.FormatConditionRuleDataBar formatConditionRuleDataBar4 = new DevExpress.XtraEditors.FormatConditionRuleDataBar(); DevExpress.XtraGrid.GridFormatRule gridFormatRule5 = new DevExpress.XtraGrid.GridFormatRule(); DevExpress.XtraEditors.FormatConditionRuleDataBar formatConditionRuleDataBar5 = new DevExpress.XtraEditors.FormatConditionRuleDataBar(); - DevExpress.XtraLayout.LayoutControlGroup layoutControl; DevExpress.XtraLayout.EmptySpaceItem emptySpaceItem1; this.DataSize = new DevExpress.XtraGrid.Columns.GridColumn(); this.DataFreeSize = new DevExpress.XtraGrid.Columns.GridColumn(); this.LogSize = new DevExpress.XtraGrid.Columns.GridColumn(); this.LogFreeSize = new DevExpress.XtraGrid.Columns.GridColumn(); this.TotalSize = new DevExpress.XtraGrid.Columns.GridColumn(); - this.DatabaseName = new DevExpress.XtraGrid.Columns.GridColumn(); - this.buttonCancel = new DevExpress.XtraEditors.SimpleButton(); - this.DatabaseBoxlayoutControl1ConvertedLayout = new DevExpress.XtraLayout.LayoutControl(); + this.searchControl1item = new DevExpress.XtraLayout.LayoutControlItem(); this.searchControl1 = new DevExpress.XtraEditors.SearchControl(); this.grid = new DevExpress.XtraGrid.GridControl(); this.view = new DevExpress.XtraGrid.Views.Grid.GridView(); + this.DatabaseName = new DevExpress.XtraGrid.Columns.GridColumn(); this.RecoveryModel = new DevExpress.XtraGrid.Columns.GridColumn(); this.LogReuseWait = new DevExpress.XtraGrid.Columns.GridColumn(); this.CreateDate = new DevExpress.XtraGrid.Columns.GridColumn(); + this.DatabaseBoxlayoutControl1ConvertedLayout = new DevExpress.XtraLayout.LayoutControl(); this.buttonRefresh = new DevExpress.XtraEditors.SimpleButton(); this.buttonOK = new DevExpress.XtraEditors.SimpleButton(); - this.searchControl1item = new DevExpress.XtraLayout.LayoutControlItem(); + this.buttonCancel = new DevExpress.XtraEditors.SimpleButton(); this.griditem = new DevExpress.XtraLayout.LayoutControlItem(); this.buttonRefreshitem = new DevExpress.XtraLayout.LayoutControlItem(); this.buttonOKitem = new DevExpress.XtraLayout.LayoutControlItem(); this.buttonCancelitem = new DevExpress.XtraLayout.LayoutControlItem(); layoutControl = new DevExpress.XtraLayout.LayoutControlGroup(); emptySpaceItem1 = new DevExpress.XtraLayout.EmptySpaceItem(); - ((System.ComponentModel.ISupportInitialize)(this.DatabaseBoxlayoutControl1ConvertedLayout)).BeginInit(); - this.DatabaseBoxlayoutControl1ConvertedLayout.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(layoutControl)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.searchControl1item)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.searchControl1.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.grid)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.view)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(layoutControl)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.searchControl1item)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.DatabaseBoxlayoutControl1ConvertedLayout)).BeginInit(); + this.DatabaseBoxlayoutControl1ConvertedLayout.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.griditem)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.buttonRefreshitem)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.buttonOKitem)).BeginInit(); @@ -128,40 +128,37 @@ private void InitializeComponent() { this.TotalSize.VisibleIndex = 5; this.TotalSize.Width = 110; // - // DatabaseName - // - this.DatabaseName.Caption = "Database"; - this.DatabaseName.FieldName = "DatabaseName"; - this.DatabaseName.Name = "DatabaseName"; - this.DatabaseName.Visible = true; - this.DatabaseName.VisibleIndex = 1; - this.DatabaseName.Width = 241; - // - // buttonCancel + // layoutControl // - this.buttonCancel.AllowFocus = false; - this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(1096, 427); - this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(76, 22); - this.buttonCancel.StyleController = this.DatabaseBoxlayoutControl1ConvertedLayout; - this.buttonCancel.TabIndex = 3; - this.buttonCancel.Text = "Cancel"; + layoutControl.AllowCustomizeChildren = false; + layoutControl.AllowHide = false; + layoutControl.EnableIndentsWithoutBorders = DevExpress.Utils.DefaultBoolean.True; + layoutControl.GroupBordersVisible = false; + layoutControl.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] { + this.searchControl1item, + this.griditem, + this.buttonRefreshitem, + this.buttonOKitem, + this.buttonCancelitem, + emptySpaceItem1}); + layoutControl.Name = "Root"; + layoutControl.Padding = new DevExpress.XtraLayout.Utils.Padding(10, 10, 5, 10); + layoutControl.ShowInCustomizationForm = false; + layoutControl.Size = new System.Drawing.Size(1184, 461); + layoutControl.TextVisible = false; // - // DatabaseBoxlayoutControl1ConvertedLayout + // searchControl1item // - this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.searchControl1); - this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.grid); - this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.buttonRefresh); - this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.buttonOK); - this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.buttonCancel); - this.DatabaseBoxlayoutControl1ConvertedLayout.Dock = System.Windows.Forms.DockStyle.Fill; - this.DatabaseBoxlayoutControl1ConvertedLayout.Location = new System.Drawing.Point(0, 0); - this.DatabaseBoxlayoutControl1ConvertedLayout.Name = "DatabaseBoxlayoutControl1ConvertedLayout"; - this.DatabaseBoxlayoutControl1ConvertedLayout.OptionsCustomizationForm.DesignTimeCustomizationFormPositionAndSize = new System.Drawing.Rectangle(968, 152, 650, 400); - this.DatabaseBoxlayoutControl1ConvertedLayout.Root = layoutControl; - this.DatabaseBoxlayoutControl1ConvertedLayout.Size = new System.Drawing.Size(1184, 461); - this.DatabaseBoxlayoutControl1ConvertedLayout.TabIndex = 5; + this.searchControl1item.Control = this.searchControl1; + this.searchControl1item.Location = new System.Drawing.Point(75, 420); + this.searchControl1item.MaxSize = new System.Drawing.Size(223, 26); + this.searchControl1item.MinSize = new System.Drawing.Size(223, 26); + this.searchControl1item.Name = "searchControl1item"; + this.searchControl1item.Padding = new DevExpress.XtraLayout.Utils.Padding(2, 2, 3, 2); + this.searchControl1item.Size = new System.Drawing.Size(223, 26); + this.searchControl1item.SizeConstraintsType = DevExpress.XtraLayout.SizeConstraintsType.Custom; + this.searchControl1item.TextSize = new System.Drawing.Size(0, 0); + this.searchControl1item.TextVisible = false; // // searchControl1 // @@ -352,6 +349,15 @@ private void InitializeComponent() { new DevExpress.XtraGrid.Columns.GridColumnSortInfo(this.TotalSize, DevExpress.Data.ColumnSortOrder.Descending)}); this.view.SelectionChanged += new DevExpress.Data.SelectionChangedEventHandler(this.GridSelectionChanged); // + // DatabaseName + // + this.DatabaseName.Caption = "Database"; + this.DatabaseName.FieldName = "DatabaseName"; + this.DatabaseName.Name = "DatabaseName"; + this.DatabaseName.Visible = true; + this.DatabaseName.VisibleIndex = 1; + this.DatabaseName.Width = 241; + // // RecoveryModel // this.RecoveryModel.Caption = "Recovery Model"; @@ -367,12 +373,12 @@ private void InitializeComponent() { // this.LogReuseWait.Caption = "Log Reuse Wait"; this.LogReuseWait.FieldName = "LogReuseWait"; - this.LogReuseWait.MaxWidth = 130; - this.LogReuseWait.MinWidth = 130; + this.LogReuseWait.MaxWidth = 150; + this.LogReuseWait.MinWidth = 150; this.LogReuseWait.Name = "LogReuseWait"; this.LogReuseWait.Visible = true; this.LogReuseWait.VisibleIndex = 3; - this.LogReuseWait.Width = 130; + this.LogReuseWait.Width = 150; // // CreateDate // @@ -388,6 +394,21 @@ private void InitializeComponent() { this.CreateDate.VisibleIndex = 4; this.CreateDate.Width = 105; // + // DatabaseBoxlayoutControl1ConvertedLayout + // + this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.searchControl1); + this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.grid); + this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.buttonRefresh); + this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.buttonOK); + this.DatabaseBoxlayoutControl1ConvertedLayout.Controls.Add(this.buttonCancel); + this.DatabaseBoxlayoutControl1ConvertedLayout.Dock = System.Windows.Forms.DockStyle.Fill; + this.DatabaseBoxlayoutControl1ConvertedLayout.Location = new System.Drawing.Point(0, 0); + this.DatabaseBoxlayoutControl1ConvertedLayout.Name = "DatabaseBoxlayoutControl1ConvertedLayout"; + this.DatabaseBoxlayoutControl1ConvertedLayout.OptionsCustomizationForm.DesignTimeCustomizationFormPositionAndSize = new System.Drawing.Rectangle(968, 152, 650, 400); + this.DatabaseBoxlayoutControl1ConvertedLayout.Root = layoutControl; + this.DatabaseBoxlayoutControl1ConvertedLayout.Size = new System.Drawing.Size(1184, 461); + this.DatabaseBoxlayoutControl1ConvertedLayout.TabIndex = 5; + // // buttonRefresh // this.buttonRefresh.AllowFocus = false; @@ -411,37 +432,16 @@ private void InitializeComponent() { this.buttonOK.TabIndex = 2; this.buttonOK.Text = "OK"; // - // layoutControl - // - layoutControl.AllowCustomizeChildren = false; - layoutControl.AllowHide = false; - layoutControl.EnableIndentsWithoutBorders = DevExpress.Utils.DefaultBoolean.True; - layoutControl.GroupBordersVisible = false; - layoutControl.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] { - this.searchControl1item, - this.griditem, - this.buttonRefreshitem, - this.buttonOKitem, - this.buttonCancelitem, - emptySpaceItem1}); - layoutControl.Name = "Root"; - layoutControl.Padding = new DevExpress.XtraLayout.Utils.Padding(10, 10, 5, 10); - layoutControl.ShowInCustomizationForm = false; - layoutControl.Size = new System.Drawing.Size(1184, 461); - layoutControl.TextVisible = false; - // - // searchControl1item + // buttonCancel // - this.searchControl1item.Control = this.searchControl1; - this.searchControl1item.Location = new System.Drawing.Point(75, 420); - this.searchControl1item.MaxSize = new System.Drawing.Size(223, 26); - this.searchControl1item.MinSize = new System.Drawing.Size(223, 26); - this.searchControl1item.Name = "searchControl1item"; - this.searchControl1item.Padding = new DevExpress.XtraLayout.Utils.Padding(2, 2, 3, 2); - this.searchControl1item.Size = new System.Drawing.Size(223, 26); - this.searchControl1item.SizeConstraintsType = DevExpress.XtraLayout.SizeConstraintsType.Custom; - this.searchControl1item.TextSize = new System.Drawing.Size(0, 0); - this.searchControl1item.TextVisible = false; + this.buttonCancel.AllowFocus = false; + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(1096, 427); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(76, 22); + this.buttonCancel.StyleController = this.DatabaseBoxlayoutControl1ConvertedLayout; + this.buttonCancel.TabIndex = 3; + this.buttonCancel.Text = "Cancel"; // // griditem // @@ -512,13 +512,13 @@ private void InitializeComponent() { this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Select Databases"; - ((System.ComponentModel.ISupportInitialize)(this.DatabaseBoxlayoutControl1ConvertedLayout)).EndInit(); - this.DatabaseBoxlayoutControl1ConvertedLayout.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(layoutControl)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.searchControl1item)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.searchControl1.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.grid)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.view)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(layoutControl)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.searchControl1item)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.DatabaseBoxlayoutControl1ConvertedLayout)).EndInit(); + this.DatabaseBoxlayoutControl1ConvertedLayout.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.griditem)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.buttonRefreshitem)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.buttonOKitem)).EndInit(); diff --git a/Forms/MainBox.Designer.cs b/Forms/MainBox.Designer.cs index 3332aaa..74a023d 100644 --- a/Forms/MainBox.Designer.cs +++ b/Forms/MainBox.Designer.cs @@ -98,6 +98,7 @@ private void InitializeComponent() { this.labelElapsedTime = new DevExpress.XtraBars.BarStaticItem(); this.buttonStopScan = new DevExpress.XtraBars.BarButtonItem(); this.buttonStopFix = new DevExpress.XtraBars.BarButtonItem(); + this.buttonAutoScroll = new DevExpress.XtraBars.BarButtonItem(); this.buttonLog = new DevExpress.XtraBars.BarButtonItem(); this.labelInfo = new DevExpress.XtraBars.BarStaticItem(); this.labelServerInfo = new DevExpress.XtraBars.BarStaticItem(); @@ -462,7 +463,7 @@ private void InitializeComponent() { // Compression.Caption = "Compression"; Compression.FieldName = "DataCompression"; - Compression.MaxWidth = 100; + Compression.MaxWidth = 120; Compression.MinWidth = 78; Compression.Name = "Compression"; Compression.OptionsColumn.AllowEdit = false; @@ -1298,6 +1299,7 @@ private void InitializeComponent() { this.statusBar.ItemLinks.Add(this.labelElapsedTime); this.statusBar.ItemLinks.Add(this.buttonStopScan); this.statusBar.ItemLinks.Add(this.buttonStopFix); + this.statusBar.ItemLinks.Add(this.buttonAutoScroll); this.statusBar.ItemLinks.Add(this.buttonLog); this.statusBar.ItemLinks.Add(this.labelInfo); this.statusBar.ItemLinks.Add(this.labelServerInfo); @@ -1375,6 +1377,16 @@ private void InitializeComponent() { this.buttonStopFix.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; this.buttonStopFix.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ButtonStopFixClick); // + // buttonAutoScroll + // + this.buttonAutoScroll.ButtonStyle = DevExpress.XtraBars.BarButtonStyle.Check; + this.buttonAutoScroll.Down = true; + this.buttonAutoScroll.Id = 41; + this.buttonAutoScroll.ImageOptions.Image = ((System.Drawing.Image)(resources.GetObject("buttonAutoScroll.ImageOptions.Image"))); + this.buttonAutoScroll.ImageOptions.LargeImage = ((System.Drawing.Image)(resources.GetObject("buttonAutoScroll.ImageOptions.LargeImage"))); + this.buttonAutoScroll.Name = "buttonAutoScroll"; + this.buttonAutoScroll.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; + // // buttonLog // this.buttonLog.Id = 26; @@ -1423,9 +1435,10 @@ private void InitializeComponent() { this.labelSavedSpace, this.labelIndexesSize, this.labelElapsedTime, - this.labelServerInfo}); + this.labelServerInfo, + this.buttonAutoScroll}); this.ribbonControl1.Location = new System.Drawing.Point(0, 0); - this.ribbonControl1.MaxItemId = 41; + this.ribbonControl1.MaxItemId = 42; this.ribbonControl1.Name = "ribbonControl1"; this.ribbonControl1.QuickToolbarItemLinks.Add(this.buttonNewConnection); this.ribbonControl1.QuickToolbarItemLinks.Add(this.buttonDatabases); @@ -1636,5 +1649,6 @@ private void InitializeComponent() { private BarStaticItem labelIndexesSize; private BarStaticItem labelElapsedTime; private BarStaticItem labelServerInfo; + private BarButtonItem buttonAutoScroll; } } \ No newline at end of file diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index ddddb4c..eba4b1a 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -315,7 +315,8 @@ private void buttonFix_ItemClick(object sender, ItemClickEventArgs e) { buttonNewConnection.Enabled = buttonOptions.Enabled = false; - buttonStopFix.Visibility = BarItemVisibility.Always; + buttonStopFix.Visibility = + buttonAutoScroll.Visibility = BarItemVisibility.Always; List selIndex = ((List)view.DataSource).Where(_ => _.IsSelected && _.FixType != IndexOp.SKIP).ToList(); @@ -375,13 +376,14 @@ private void FixIndexesProgressChanged(object sender, ProgressChangedEventArgs e taskbar.ProgressCurrentValue = e.ProgressPercentage + 1; UpdateProgressStats(); - if (e.UserState != null) { + if (e.UserState != null && buttonAutoScroll.Down) { Index index = (Index)e.UserState; var rowHandle = view.FindRow(index); if (rowHandle != GridControl.InvalidRowHandle) { - view.RefreshRow(rowHandle); - view.SelectRow(rowHandle); - view.MakeRowVisible(rowHandle); + if (view.IsRowVisible(rowHandle) == RowVisibleState.Hidden) { + view.MoveNextPage(); + view.MakeRowVisible(rowHandle); + } } } @@ -429,14 +431,6 @@ private void FixIndexes(object sender, DoWorkEventArgs e) { index.Progress = Resources.IconError; _ps.Errors++; } - else { - if (Settings.Options.DelayAfterFix > 0 && i < indexes.Count - 1) { - _workerFix.ReportProgress(i, index); - index.Progress = Resources.IconDelay; - Thread.Sleep(Settings.Options.DelayAfterFix); - index.Progress = Resources.IconOk; - } - } _workerFix.ReportProgress(i, index); } @@ -455,7 +449,8 @@ private void FixIndexesFinish(object sender, RunWorkerCompletedEventArgs e) { buttonFix.Enabled = false; - buttonStopFix.Visibility = BarItemVisibility.Never; + buttonStopFix.Visibility = + buttonAutoScroll.Visibility = BarItemVisibility.Never; UpdateProgressStats(); Output.Current.Add("Done!"); @@ -938,7 +933,9 @@ private void ButtonStopFixClick(object sender, ItemClickEventArgs e) { Output.Current.Add("Canceling..."); QueryEngine.KillActiveSessions(); _workerFix.CancelAsync(); - buttonStopFix.Visibility = BarItemVisibility.Never; + + buttonStopFix.Visibility = + buttonAutoScroll.Visibility = BarItemVisibility.Never; } private void ButtonCopyFixClick(object sender, ItemClickEventArgs e) { diff --git a/Forms/MainBox.resx b/Forms/MainBox.resx index 230af7a..2992251 100644 --- a/Forms/MainBox.resx +++ b/Forms/MainBox.resx @@ -237,6 +237,27 @@ 455, 20 + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m + dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAARdEVYdFRpdGxlAERvd247QXJyb3c7vfyCWAAAAHNJ + REFUOE/VjcENgDAMA7tg1mEAlmAEVmC7gCulosZAI148DqkX2xR3/4SUGaS0eXOGM4GUPxs4jsbhQawO + 4IMHHd+o5TaQHGnlbgDgSGGmK4PuARCi0m0ZXARAeKQMpASnEZvWRWaAlMHTnwMpM0g5jpcdXxzKXDJZ + gvUAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m + dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAARdEVYdFRpdGxlAERvd247QXJyb3c7vfyCWAAAAOlJ + REFUWEfFztsRwkAMQ9E0mHYogCYogRbobhl9hEmU63jzMh9nBhTb2qG19lcYVsKwEoaVMKyEYSUMI+Pz + 0zK+k8EwQoXOdzIYRqjQ+U4GwwgVOt/JYBihQuc7GQwjVOh8J/P7QcfuMnXK/AGjD95kxAeIPtrw1Rbl + svgjGrKlq6zKZRWIhm35LCwXDEVLduSosFwwnGjZju21WS4YzumIHe2VlguGTsfseKarXDAkOmolke5y + wTCi41bmdpULhltUYqWHywXDjMquKBcMM4/3a/6Iw+WCYa+z5YJhJQwrYVgJw0oY1mnDF/KvX9TArLt9 + AAAAAElFTkSuQmCC + + 238, 18 diff --git a/Forms/SettingsBox.Designer.cs b/Forms/SettingsBox.Designer.cs index 2eca7c5..f6845cb 100644 --- a/Forms/SettingsBox.Designer.cs +++ b/Forms/SettingsBox.Designer.cs @@ -37,8 +37,6 @@ private void InitializeComponent() { DevExpress.XtraEditors.LabelControl labelControl6; DevExpress.XtraEditors.GroupControl db3; DevExpress.XtraEditors.GroupControl groupControl3; - DevExpress.XtraEditors.LabelControl labelControl1; - DevExpress.XtraEditors.LabelControl labelControl3; DevExpress.XtraEditors.LabelControl labelPadIndex; DevExpress.XtraEditors.LabelControl labelControl7; DevExpress.XtraEditors.LabelControl labelControl13; @@ -74,8 +72,6 @@ private void InitializeComponent() { this.boxScanNonClusteredColumnstore = new DevExpress.XtraEditors.CheckEdit(); this.boxIgnoreReadOnlyFL = new DevExpress.XtraEditors.CheckEdit(); this.boxScanHeap = new DevExpress.XtraEditors.CheckEdit(); - this.boxDelayAfterFix = new DevExpress.XtraEditors.SpinEdit(); - this.boxMultiThreadingCount = new DevExpress.XtraEditors.SpinEdit(); this.boxPadIndex = new DevExpress.XtraEditors.CheckEdit(); this.boxNoRecompute = new DevExpress.XtraEditors.ComboBoxEdit(); this.boxStatsSamplePercent = new DevExpress.XtraEditors.SpinEdit(); @@ -110,8 +106,6 @@ private void InitializeComponent() { labelControl6 = new DevExpress.XtraEditors.LabelControl(); db3 = new DevExpress.XtraEditors.GroupControl(); groupControl3 = new DevExpress.XtraEditors.GroupControl(); - labelControl1 = new DevExpress.XtraEditors.LabelControl(); - labelControl3 = new DevExpress.XtraEditors.LabelControl(); labelPadIndex = new DevExpress.XtraEditors.LabelControl(); labelControl7 = new DevExpress.XtraEditors.LabelControl(); labelControl13 = new DevExpress.XtraEditors.LabelControl(); @@ -153,8 +147,6 @@ private void InitializeComponent() { ((System.ComponentModel.ISupportInitialize)(this.boxScanHeap.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(groupControl3)).BeginInit(); groupControl3.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.boxDelayAfterFix.Properties)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.boxMultiThreadingCount.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxPadIndex.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxNoRecompute.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxStatsSamplePercent.Properties)).BeginInit(); @@ -227,7 +219,7 @@ private void InitializeComponent() { // buttonCancel.AllowFocus = false; buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - buttonCancel.Location = new System.Drawing.Point(642, 542); + buttonCancel.Location = new System.Drawing.Point(642, 573); buttonCancel.Name = "buttonCancel"; buttonCancel.Size = new System.Drawing.Size(75, 23); buttonCancel.TabIndex = 0; @@ -237,7 +229,7 @@ private void InitializeComponent() { // buttonRestore // buttonRestore.AllowFocus = false; - buttonRestore.Location = new System.Drawing.Point(12, 542); + buttonRestore.Location = new System.Drawing.Point(12, 573); buttonRestore.Name = "buttonRestore"; buttonRestore.Size = new System.Drawing.Size(75, 23); buttonRestore.TabIndex = 0; @@ -260,13 +252,13 @@ private void InitializeComponent() { groupControl1.Controls.Add(this.labelSize); groupControl1.Location = new System.Drawing.Point(12, 4); groupControl1.Name = "groupControl1"; - groupControl1.Size = new System.Drawing.Size(396, 205); + groupControl1.Size = new System.Drawing.Size(396, 228); groupControl1.TabIndex = 8; groupControl1.Text = "Filters"; // // labelSkipThreshold // - this.labelSkipThreshold.Location = new System.Drawing.Point(211, 91); + this.labelSkipThreshold.Location = new System.Drawing.Point(211, 104); this.labelSkipThreshold.Name = "labelSkipThreshold"; this.labelSkipThreshold.Size = new System.Drawing.Size(25, 13); this.labelSkipThreshold.TabIndex = 33; @@ -275,7 +267,7 @@ private void InitializeComponent() { // boxSkipThreshold // this.boxSkipThreshold.EditValue = ""; - this.boxSkipThreshold.Location = new System.Drawing.Point(13, 88); + this.boxSkipThreshold.Location = new System.Drawing.Point(13, 101); this.boxSkipThreshold.Name = "boxSkipThreshold"; this.boxSkipThreshold.Properties.AllowFocused = false; this.boxSkipThreshold.Properties.Appearance.Options.UseTextOptions = true; @@ -290,7 +282,7 @@ private void InitializeComponent() { // boxSecondThreshold // this.boxSecondThreshold.EditValue = ""; - this.boxSecondThreshold.Location = new System.Drawing.Point(13, 140); + this.boxSecondThreshold.Location = new System.Drawing.Point(13, 159); this.boxSecondThreshold.Name = "boxSecondThreshold"; this.boxSecondThreshold.Properties.AllowFocused = false; this.boxSecondThreshold.Properties.Appearance.Options.UseTextOptions = true; @@ -305,7 +297,7 @@ private void InitializeComponent() { // boxFirstThreshold // this.boxFirstThreshold.EditValue = ""; - this.boxFirstThreshold.Location = new System.Drawing.Point(13, 114); + this.boxFirstThreshold.Location = new System.Drawing.Point(13, 130); this.boxFirstThreshold.Name = "boxFirstThreshold"; this.boxFirstThreshold.Properties.AllowFocused = false; this.boxFirstThreshold.Properties.Appearance.Options.UseTextOptions = true; @@ -319,7 +311,7 @@ private void InitializeComponent() { // // labelFirstThreshold // - this.labelFirstThreshold.Location = new System.Drawing.Point(211, 117); + this.labelFirstThreshold.Location = new System.Drawing.Point(211, 133); this.labelFirstThreshold.Name = "labelFirstThreshold"; this.labelFirstThreshold.Size = new System.Drawing.Size(25, 13); this.labelFirstThreshold.TabIndex = 3; @@ -327,7 +319,7 @@ private void InitializeComponent() { // // labelSecondThreshold // - this.labelSecondThreshold.Location = new System.Drawing.Point(211, 143); + this.labelSecondThreshold.Location = new System.Drawing.Point(211, 162); this.labelSecondThreshold.Name = "labelSecondThreshold"; this.labelSecondThreshold.Size = new System.Drawing.Size(25, 13); this.labelSecondThreshold.TabIndex = 8; @@ -379,7 +371,7 @@ private void InitializeComponent() { // boxThreshold // this.boxThreshold.EditValue = new DevExpress.XtraEditors.Repository.TrackBarRange(1, 1); - this.boxThreshold.Location = new System.Drawing.Point(6, 171); + this.boxThreshold.Location = new System.Drawing.Point(6, 190); this.boxThreshold.Name = "boxThreshold"; this.boxThreshold.Properties.AllowFocused = false; this.boxThreshold.Properties.HighlightSelectedRange = false; @@ -408,7 +400,7 @@ private void InitializeComponent() { groupControl2.Controls.Add(this.boxConnectionTimeout); groupControl2.Controls.Add(labelControl6); groupControl2.Controls.Add(this.boxCommandTimeout); - groupControl2.Location = new System.Drawing.Point(414, 453); + groupControl2.Location = new System.Drawing.Point(414, 395); groupControl2.Name = "groupControl2"; groupControl2.Size = new System.Drawing.Size(303, 81); groupControl2.TabIndex = 14; @@ -512,15 +504,15 @@ private void InitializeComponent() { db3.Controls.Add(this.boxScanNonClusteredColumnstore); db3.Controls.Add(this.boxIgnoreReadOnlyFL); db3.Controls.Add(this.boxScanHeap); - db3.Location = new System.Drawing.Point(12, 215); + db3.Location = new System.Drawing.Point(12, 239); db3.Name = "db3"; - db3.Size = new System.Drawing.Size(396, 145); + db3.Size = new System.Drawing.Size(396, 150); db3.TabIndex = 16; db3.Text = "Object Scan"; // // boxShowOnlyMore1000Rows // - this.boxShowOnlyMore1000Rows.Location = new System.Drawing.Point(228, 115); + this.boxShowOnlyMore1000Rows.Location = new System.Drawing.Point(228, 117); this.boxShowOnlyMore1000Rows.Name = "boxShowOnlyMore1000Rows"; this.boxShowOnlyMore1000Rows.Properties.AllowFocused = false; this.boxShowOnlyMore1000Rows.Properties.Caption = " ONLY WHEN ROWS > 1000"; @@ -530,7 +522,7 @@ private void InitializeComponent() { // // boxIgnoreHeapWithCompression // - this.boxIgnoreHeapWithCompression.Location = new System.Drawing.Point(13, 115); + this.boxIgnoreHeapWithCompression.Location = new System.Drawing.Point(13, 117); this.boxIgnoreHeapWithCompression.Name = "boxIgnoreHeapWithCompression"; this.boxIgnoreHeapWithCompression.Properties.AllowFocused = false; this.boxIgnoreHeapWithCompression.Properties.Caption = " IGNORE HEAP WITH COMPRESSION"; @@ -626,10 +618,6 @@ private void InitializeComponent() { // // groupControl3 // - groupControl3.Controls.Add(this.boxDelayAfterFix); - groupControl3.Controls.Add(labelControl1); - groupControl3.Controls.Add(this.boxMultiThreadingCount); - groupControl3.Controls.Add(labelControl3); groupControl3.Controls.Add(labelPadIndex); groupControl3.Controls.Add(this.boxPadIndex); groupControl3.Controls.Add(this.boxNoRecompute); @@ -658,96 +646,10 @@ private void InitializeComponent() { groupControl3.Controls.Add(this.boxOnline); groupControl3.Location = new System.Drawing.Point(414, 4); groupControl3.Name = "groupControl3"; - groupControl3.Size = new System.Drawing.Size(303, 443); + groupControl3.Size = new System.Drawing.Size(303, 385); groupControl3.TabIndex = 17; groupControl3.Text = "Indexes"; // - // boxDelayAfterFix - // - this.boxDelayAfterFix.EditValue = new decimal(new int[] { - 0, - 0, - 0, - 0}); - this.boxDelayAfterFix.Location = new System.Drawing.Point(200, 413); - this.boxDelayAfterFix.Name = "boxDelayAfterFix"; - this.boxDelayAfterFix.Properties.AllowFocused = false; - this.boxDelayAfterFix.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.False; - this.boxDelayAfterFix.Properties.Appearance.Options.UseTextOptions = true; - this.boxDelayAfterFix.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center; - this.boxDelayAfterFix.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { - new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); - this.boxDelayAfterFix.Properties.DisplayFormat.FormatString = "N00"; - this.boxDelayAfterFix.Properties.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Custom; - this.boxDelayAfterFix.Properties.EditFormat.FormatString = "n0"; - this.boxDelayAfterFix.Properties.EditFormat.FormatType = DevExpress.Utils.FormatType.Custom; - this.boxDelayAfterFix.Properties.Increment = new decimal(new int[] { - 100, - 0, - 0, - 0}); - this.boxDelayAfterFix.Properties.IsFloatValue = false; - this.boxDelayAfterFix.Properties.Mask.EditMask = "N00"; - this.boxDelayAfterFix.Properties.MaxValue = new decimal(new int[] { - 5000, - 0, - 0, - 0}); - this.boxDelayAfterFix.Size = new System.Drawing.Size(88, 20); - this.boxDelayAfterFix.TabIndex = 32; - this.boxDelayAfterFix.TabStop = false; - // - // labelControl1 - // - labelControl1.Location = new System.Drawing.Point(14, 416); - labelControl1.Name = "labelControl1"; - labelControl1.Size = new System.Drawing.Size(122, 13); - labelControl1.TabIndex = 31; - labelControl1.Text = "DELAY_MS_AFTER_FIX ="; - // - // boxMultiThreadingCount - // - this.boxMultiThreadingCount.EditValue = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.boxMultiThreadingCount.Location = new System.Drawing.Point(200, 383); - this.boxMultiThreadingCount.Name = "boxMultiThreadingCount"; - this.boxMultiThreadingCount.Properties.AllowFocused = false; - this.boxMultiThreadingCount.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.False; - this.boxMultiThreadingCount.Properties.Appearance.Options.UseTextOptions = true; - this.boxMultiThreadingCount.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center; - this.boxMultiThreadingCount.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { - new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); - this.boxMultiThreadingCount.Properties.DisplayFormat.FormatString = "N00"; - this.boxMultiThreadingCount.Properties.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Custom; - this.boxMultiThreadingCount.Properties.EditFormat.FormatString = "n0"; - this.boxMultiThreadingCount.Properties.EditFormat.FormatType = DevExpress.Utils.FormatType.Custom; - this.boxMultiThreadingCount.Properties.IsFloatValue = false; - this.boxMultiThreadingCount.Properties.Mask.EditMask = "N00"; - this.boxMultiThreadingCount.Properties.MaxValue = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.boxMultiThreadingCount.Properties.MinValue = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.boxMultiThreadingCount.Size = new System.Drawing.Size(88, 20); - this.boxMultiThreadingCount.TabIndex = 30; - this.boxMultiThreadingCount.TabStop = false; - // - // labelControl3 - // - labelControl3.Location = new System.Drawing.Point(14, 386); - labelControl3.Name = "labelControl3"; - labelControl3.Size = new System.Drawing.Size(173, 13); - labelControl3.TabIndex = 28; - labelControl3.Text = "MULTI-THREADING_PROCESSING ="; - // // labelPadIndex // labelPadIndex.Location = new System.Drawing.Point(14, 189); @@ -1127,7 +1029,7 @@ private void InitializeComponent() { " "}); this.boxExcludeObject.Properties.ShowDropDown = false; this.boxExcludeObject.Properties.ValidateToken += new DevExpress.XtraEditors.TokenEditValidateTokenEventHandler(this.TokenValidate); - this.boxExcludeObject.Size = new System.Drawing.Size(343, 20); + this.boxExcludeObject.Size = new System.Drawing.Size(652, 20); this.boxExcludeObject.TabIndex = 8; // // boxExcludeSchemas @@ -1153,7 +1055,7 @@ private void InitializeComponent() { // this.buttonOK.AllowFocus = false; this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.buttonOK.Location = new System.Drawing.Point(561, 542); + this.buttonOK.Location = new System.Drawing.Point(561, 573); this.buttonOK.Name = "buttonOK"; this.buttonOK.Size = new System.Drawing.Size(75, 23); this.buttonOK.TabIndex = 1; @@ -1176,7 +1078,7 @@ private void InitializeComponent() { " "}); this.boxIncludeObject.Properties.ShowDropDown = false; this.boxIncludeObject.Properties.ValidateToken += new DevExpress.XtraEditors.TokenEditValidateTokenEventHandler(this.TokenValidate); - this.boxIncludeObject.Size = new System.Drawing.Size(343, 20); + this.boxIncludeObject.Size = new System.Drawing.Size(652, 20); this.boxIncludeObject.TabIndex = 15; // // groupControl4 @@ -1185,7 +1087,7 @@ private void InitializeComponent() { this.groupControl4.Controls.Add(pictureBox1); this.groupControl4.Controls.Add(this.boxExcludeSchemas); this.groupControl4.Controls.Add(this.boxIncludeSchemas); - this.groupControl4.Location = new System.Drawing.Point(12, 366); + this.groupControl4.Location = new System.Drawing.Point(12, 395); this.groupControl4.Name = "groupControl4"; this.groupControl4.Size = new System.Drawing.Size(396, 81); this.groupControl4.TabIndex = 18; @@ -1197,15 +1099,15 @@ private void InitializeComponent() { this.groupControl5.Controls.Add(pictureBox4); this.groupControl5.Controls.Add(this.boxIncludeObject); this.groupControl5.Controls.Add(this.boxExcludeObject); - this.groupControl5.Location = new System.Drawing.Point(12, 453); + this.groupControl5.Location = new System.Drawing.Point(12, 482); this.groupControl5.Name = "groupControl5"; - this.groupControl5.Size = new System.Drawing.Size(396, 81); + this.groupControl5.Size = new System.Drawing.Size(705, 81); this.groupControl5.TabIndex = 19; this.groupControl5.Text = "Object Filter (schema.table OR table OR %pattern%)"; // // boxShowSettingsWhenConnectionChanged // - this.boxShowSettingsWhenConnectionChanged.Location = new System.Drawing.Point(93, 544); + this.boxShowSettingsWhenConnectionChanged.Location = new System.Drawing.Point(93, 575); this.boxShowSettingsWhenConnectionChanged.Name = "boxShowSettingsWhenConnectionChanged"; this.boxShowSettingsWhenConnectionChanged.Properties.AllowFocused = false; this.boxShowSettingsWhenConnectionChanged.Properties.Caption = "Open dialog when connection string changed"; @@ -1217,7 +1119,7 @@ private void InitializeComponent() { // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(726, 575); + this.ClientSize = new System.Drawing.Size(726, 605); this.Controls.Add(this.boxShowSettingsWhenConnectionChanged); this.Controls.Add(this.groupControl5); this.Controls.Add(this.groupControl4); @@ -1269,8 +1171,6 @@ private void InitializeComponent() { ((System.ComponentModel.ISupportInitialize)(groupControl3)).EndInit(); groupControl3.ResumeLayout(false); groupControl3.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.boxDelayAfterFix.Properties)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.boxMultiThreadingCount.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxPadIndex.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxNoRecompute.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxStatsSamplePercent.Properties)).EndInit(); @@ -1346,10 +1246,8 @@ private void InitializeComponent() { private DevExpress.XtraEditors.CheckEdit boxPadIndex; private DevExpress.XtraEditors.LabelControl labelSkipThreshold; private DevExpress.XtraEditors.ComboBoxEdit boxSkipThreshold; - private DevExpress.XtraEditors.SpinEdit boxMultiThreadingCount; private DevExpress.XtraEditors.CheckEdit boxShowSettingsWhenConnectionChanged; private DevExpress.XtraEditors.CheckEdit boxIgnoreHeapWithCompression; - private DevExpress.XtraEditors.SpinEdit boxDelayAfterFix; private DevExpress.XtraEditors.CheckEdit boxShowOnlyMore1000Rows; } } \ No newline at end of file diff --git a/Forms/SettingsBox.cs b/Forms/SettingsBox.cs index 0e65d5d..61e52ed 100644 --- a/Forms/SettingsBox.cs +++ b/Forms/SettingsBox.cs @@ -51,9 +51,6 @@ private void UpdateControls(Options o) { boxPadIndex.Checked = o.PadIndex; boxSortInTempDb.Checked = o.SortInTempDb; boxLobCompaction.Checked = o.LobCompaction; - boxMultiThreadingCount.Value = o.DelayAfterFix; - boxDelayAfterFix.Value = o.DelayAfterFix; - boxMultiThreadingCount.Value = o.MultiThreadingCount; boxMaxDod.Value = o.MaxDop; boxStatsSamplePercent.Value = o.SampleStatsPercent; boxConnectionTimeout.Value = o.ConnectionTimeout; @@ -94,8 +91,6 @@ public Options GetSettings() { MinIndexSize = boxMinIndexSize.Value.Minimum, PreDescribeSize = boxMinIndexSize.Value.Maximum, MaxIndexSize = boxMaxIndexSize.Value, - DelayAfterFix = (int)boxDelayAfterFix.Value, - MultiThreadingCount = (int)boxMultiThreadingCount.Value, MaxDop = (int)boxMaxDod.Value, Online = boxOnline.Checked, PadIndex = boxPadIndex.Checked, diff --git a/Forms/SettingsBox.resx b/Forms/SettingsBox.resx index b22528c..17e71a0 100644 --- a/Forms/SettingsBox.resx +++ b/Forms/SettingsBox.resx @@ -156,12 +156,6 @@ False - - False - - - False - False diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index f15e50d..4bb917b 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -273,16 +273,6 @@ internal static System.Drawing.Bitmap IconDatabases { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap IconDelay { - get { - object obj = ResourceManager.GetObject("IconDelay", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index f84012a..85ff687 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -355,9 +355,6 @@ ..\Images\icon_copy.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Images\icon_delay.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Images\icon_error.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/Settings/Options.cs b/Settings/Options.cs index e10c845..72ce4de 100644 --- a/Settings/Options.cs +++ b/Settings/Options.cs @@ -17,8 +17,6 @@ public class Options { private int _maxIndexSize = 8192; private int _connectionTimeout = 15; private int _commandTimeout = 120; - private int _delayAfterFix; - private int _multiThreadingCount = 1; private int _maxDop; private int _fillFactor; private int _sampleStatsPercent = 100; @@ -89,18 +87,6 @@ public int SecondThreshold { set => UpdateThreshold(_firstThreshold, value); } - [XmlAttribute] - public int DelayAfterFix { - get => _delayAfterFix; - set => _delayAfterFix = value.IsBetween(0, 5000) ? value : _delayAfterFix; - } - - [XmlAttribute] - public int MultiThreadingCount { - get => _multiThreadingCount; - set => _multiThreadingCount = value.IsBetween(1, 1) ? value : _multiThreadingCount; - } - [XmlAttribute] public int MaxDop { get => _maxDop; From cbcbca0eb461d5651f0e824ccdd5473271f6067d Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 27 Jun 2021 22:27:17 +0300 Subject: [PATCH 06/19] Bugfix during truncate table execution --- Forms/MainBox.cs | 2 +- Properties/Resources.Designer.cs | 9 +++++++++ Properties/Resources.resx | 3 +++ Server/Index.cs | 5 ++++- Server/Query.cs | 18 ++++++++++++++++++ Server/QueryEngine.cs | 1 + 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index eba4b1a..d066cba 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -633,7 +633,7 @@ private List GetIndexOperations(Index ix) { } } - if (ix.IsTable) { + if (ix.IsTable && !ix.IsFKs && ((ix.IsPartitioned && Settings.ServerInfo.MajorVersion >= ServerVersion.Sql2016) || !ix.IsPartitioned)) { i.Add(IndexOp.TRUNCATE_TABLE); } diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index 4bb917b..48cc45f 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -615,6 +615,15 @@ internal static string IsFiltered { } } + /// + /// Looks up a localized string similar to IsFKs. + /// + internal static string IsFKs { + get { + return ResourceManager.GetString("IsFKs", resourceCulture); + } + } + /// /// Looks up a localized string similar to IsLob. /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index 85ff687..e0068dc 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -409,4 +409,7 @@ IsTable + + IsFKs + \ No newline at end of file diff --git a/Server/Index.cs b/Server/Index.cs index b64e379..e23e9e8 100644 --- a/Server/Index.cs +++ b/Server/Index.cs @@ -50,6 +50,7 @@ public class Index { public bool IsAllowOnlineRebuild { get; set; } public bool IsAllowCompression { get; set; } public bool IsTable { get; set; } + public bool IsFKs { get; set; } public bool IsColumnstore => (IndexType == IndexType.CLUSTERED_COLUMNSTORE || IndexType == IndexType.NONCLUSTERED_COLUMNSTORE); public string Error { get; set; } @@ -172,7 +173,9 @@ public string GetQuery() { break; case IndexOp.TRUNCATE_TABLE: - sql = $"TRUNCATE TABLE {objectName};"; + sql = IsPartitioned + ? $"TRUNCATE TABLE {objectName} WITH (PARTITIONS ({partition}));" + : $"TRUNCATE TABLE {objectName};"; break; case IndexOp.UPDATE_STATISTICS_SAMPLE: diff --git a/Server/Query.cs b/Server/Query.cs index aa592ff..9e43ae8 100644 --- a/Server/Query.cs +++ b/Server/Query.cs @@ -255,6 +255,22 @@ ObjectID INT NOT NULL DECLARE @MINUTE INT SET @MINUTE = DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()) +IF OBJECT_ID('tempdb.dbo.#FKs') IS NOT NULL + DROP TABLE #FKs + +CREATE TABLE #FKs (ObjectID INT PRIMARY KEY) +INSERT INTO #FKs +SELECT i.ObjectID +FROM ( + SELECT DISTINCT ObjectID + FROM #Indexes +) i +WHERE EXISTS( + SELECT * + FROM sys.foreign_keys f WITH(NOLOCK) + WHERE f.[referenced_object_id] = i.ObjectID + ) + SELECT i.ObjectID , i.IndexID , i.IndexName @@ -284,6 +300,7 @@ SELECT i.ObjectID , CreateDate = DATEADD(MINUTE, -@MINUTE, o.[create_date]) , ModifyDate = DATEADD(MINUTE, -@MINUTE, o.[modify_date]) , IsTable = CAST(CASE WHEN o.[type] = 'U' THEN 1 ELSE 0 END AS BIT) + , IsFKs = CAST(CASE WHEN fk.ObjectID IS NULL THEN 0 ELSE 1 END AS BIT) , i.IsUnique , i.IsPK , i.FillFactorValue @@ -296,6 +313,7 @@ SELECT i.ObjectID FROM #Indexes i JOIN sys.objects o WITH(NOLOCK) ON o.[object_id] = i.ObjectID JOIN sys.schemas s WITH(NOLOCK) ON s.[schema_id] = o.[schema_id] +LEFT JOIN #FKs fk ON fk.ObjectID = i.ObjectID LEFT JOIN #Stats ss ON ss.ObjectID = i.ObjectID AND ss.IndexID = i.IndexID LEFT JOIN #AggColumns a ON a.ObjectID = i.ObjectID AND a.IndexID = i.IndexID LEFT JOIN #Sparse p ON p.ObjectID = i.ObjectID diff --git a/Server/QueryEngine.cs b/Server/QueryEngine.cs index 91177c5..010c7b4 100644 --- a/Server/QueryEngine.cs +++ b/Server/QueryEngine.cs @@ -238,6 +238,7 @@ public static List GetIndexes(SqlConnection connection) { Fragmentation = _.Field(Resources.Fragmentation), PageSpaceUsed = _.Field(Resources.PageSpaceUsed), IsTable = _.Field(Resources.IsTable), + IsFKs = _.Field(Resources.IsFKs), IsAllowReorganize = _.Field(Resources.IsAllowPageLocks) && indexType != IndexType.HEAP, IsAllowOnlineRebuild = isOnlineRebuild, IsAllowCompression = Settings.ServerInfo.IsCompressionAvailable && !_.Field(Resources.IsSparse), From 477fcb1d08e0c891e97b379ef95a859533dc37f8 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 27 Jun 2021 22:34:43 +0300 Subject: [PATCH 07/19] Fixed 'STATISTICS_NORECOMPUTE' is not a recognized ALTER INDEX REBUILD PARTITION option --- Server/Index.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/Index.cs b/Server/Index.cs index e23e9e8..7921864 100644 --- a/Server/Index.cs +++ b/Server/Index.cs @@ -145,7 +145,7 @@ public string GetQuery() { (IsPartitioned || Settings.Options.FillFactor == 0 ? "" : $"FILLFACTOR = {Settings.Options.FillFactor}, ") + - (IndexType == IndexType.HEAP + (IndexType == IndexType.HEAP || IsPartitioned ? "" : $"STATISTICS_NORECOMPUTE = {nr}, ") + (!IsAllowCompression From 9979477a1f23facb63a2fa7c42d453c47acd54a3 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Mon, 28 Jun 2021 07:27:52 +0300 Subject: [PATCH 08/19] Additional tooltips for status bar --- Forms/MainBox.Designer.cs | 59 +++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/Forms/MainBox.Designer.cs b/Forms/MainBox.Designer.cs index 74a023d..f53d4d0 100644 --- a/Forms/MainBox.Designer.cs +++ b/Forms/MainBox.Designer.cs @@ -84,7 +84,23 @@ private void InitializeComponent() { DevExpress.XtraEditors.FormatConditionRuleDataBar formatConditionRuleDataBar11 = new DevExpress.XtraEditors.FormatConditionRuleDataBar(); DevExpress.XtraGrid.GridFormatRule gridFormatRule13 = new DevExpress.XtraGrid.GridFormatRule(); DevExpress.XtraEditors.FormatConditionRuleDataBar formatConditionRuleDataBar12 = new DevExpress.XtraEditors.FormatConditionRuleDataBar(); + DevExpress.Utils.SuperToolTip superToolTip1 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem1 = new DevExpress.Utils.ToolTipTitleItem(); + DevExpress.Utils.SuperToolTip superToolTip2 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem2 = new DevExpress.Utils.ToolTipTitleItem(); + DevExpress.Utils.SuperToolTip superToolTip3 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem3 = new DevExpress.Utils.ToolTipTitleItem(); + DevExpress.Utils.SuperToolTip superToolTip4 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem4 = new DevExpress.Utils.ToolTipTitleItem(); + DevExpress.Utils.SuperToolTip superToolTip5 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem5 = new DevExpress.Utils.ToolTipTitleItem(); + DevExpress.Utils.SuperToolTip superToolTip6 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem6 = new DevExpress.Utils.ToolTipTitleItem(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainBox)); + DevExpress.Utils.SuperToolTip superToolTip7 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem7 = new DevExpress.Utils.ToolTipTitleItem(); + DevExpress.Utils.SuperToolTip superToolTip8 = new DevExpress.Utils.SuperToolTip(); + DevExpress.Utils.ToolTipTitleItem toolTipTitleItem8 = new DevExpress.Utils.ToolTipTitleItem(); this.popupIndexOperation = new DevExpress.XtraEditors.Repository.RepositoryItemLookUpEdit(); this.grid = new DevExpress.XtraGrid.GridControl(); this.view = new DevExpress.XtraGrid.Views.Grid.GridView(); @@ -832,13 +848,13 @@ private void InitializeComponent() { // this.grid.Dock = System.Windows.Forms.DockStyle.Fill; this.grid.Font = new System.Drawing.Font("Tahoma", 9F); - this.grid.Location = new System.Drawing.Point(0, 27); + this.grid.Location = new System.Drawing.Point(0, 32); this.grid.MainView = this.view; this.grid.Margin = new System.Windows.Forms.Padding(3, 8, 3, 3); this.grid.Name = "grid"; this.grid.RepositoryItems.AddRange(new DevExpress.XtraEditors.Repository.RepositoryItem[] { this.popupIndexOperation}); - this.grid.Size = new System.Drawing.Size(1190, 741); + this.grid.Size = new System.Drawing.Size(1190, 746); this.grid.TabIndex = 2; this.grid.ToolTipController = this.gridToolTipController; this.grid.ViewCollection.AddRange(new DevExpress.XtraGrid.Views.Base.BaseView[] { @@ -1287,6 +1303,8 @@ private void InitializeComponent() { // // gridToolTipController // + this.gridToolTipController.ToolTipAnchor = DevExpress.Utils.ToolTipAnchor.Object; + this.gridToolTipController.ToolTipLocation = DevExpress.Utils.ToolTipLocation.TopCenter; this.gridToolTipController.GetActiveObjectInfo += new DevExpress.Utils.ToolTipControllerGetActiveObjectInfoEventHandler(this.GetActiveObjectInfo); // // statusBar @@ -1303,10 +1321,10 @@ private void InitializeComponent() { this.statusBar.ItemLinks.Add(this.buttonLog); this.statusBar.ItemLinks.Add(this.labelInfo); this.statusBar.ItemLinks.Add(this.labelServerInfo); - this.statusBar.Location = new System.Drawing.Point(0, 768); + this.statusBar.Location = new System.Drawing.Point(0, 778); this.statusBar.Name = "statusBar"; this.statusBar.Ribbon = this.ribbonControl1; - this.statusBar.Size = new System.Drawing.Size(1190, 31); + this.statusBar.Size = new System.Drawing.Size(1190, 21); this.statusBar.ToolTipController = this.toolTipController; // // labelDatabases @@ -1316,6 +1334,9 @@ private void InitializeComponent() { this.labelDatabases.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconDatabases; this.labelDatabases.Name = "labelDatabases"; this.labelDatabases.PaintStyle = DevExpress.XtraBars.BarItemPaintStyle.CaptionGlyph; + toolTipTitleItem1.Text = "Databases"; + superToolTip1.Items.Add(toolTipTitleItem1); + this.labelDatabases.SuperTip = superToolTip1; this.labelDatabases.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // labelErrors @@ -1324,6 +1345,9 @@ private void InitializeComponent() { this.labelErrors.Id = 29; this.labelErrors.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconErrors; this.labelErrors.Name = "labelErrors"; + toolTipTitleItem2.Text = "Errors"; + superToolTip2.Items.Add(toolTipTitleItem2); + this.labelErrors.SuperTip = superToolTip2; this.labelErrors.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // labelIndexes @@ -1333,6 +1357,9 @@ private void InitializeComponent() { this.labelIndexes.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconIndexes; this.labelIndexes.Name = "labelIndexes"; this.labelIndexes.PaintStyle = DevExpress.XtraBars.BarItemPaintStyle.CaptionGlyph; + toolTipTitleItem3.Text = "Indexes"; + superToolTip3.Items.Add(toolTipTitleItem3); + this.labelIndexes.SuperTip = superToolTip3; this.labelIndexes.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // labelIndexesSize @@ -1341,6 +1368,9 @@ private void InitializeComponent() { this.labelIndexesSize.Id = 33; this.labelIndexesSize.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconIndexesSize; this.labelIndexesSize.Name = "labelIndexesSize"; + toolTipTitleItem4.Text = "Index Size"; + superToolTip4.Items.Add(toolTipTitleItem4); + this.labelIndexesSize.SuperTip = superToolTip4; this.labelIndexesSize.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // labelSavedSpace @@ -1349,6 +1379,9 @@ private void InitializeComponent() { this.labelSavedSpace.Id = 31; this.labelSavedSpace.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconSavedSpace; this.labelSavedSpace.Name = "labelSavedSpace"; + toolTipTitleItem5.Text = "Saved Space"; + superToolTip5.Items.Add(toolTipTitleItem5); + this.labelSavedSpace.SuperTip = superToolTip5; this.labelSavedSpace.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // labelElapsedTime @@ -1357,6 +1390,9 @@ private void InitializeComponent() { this.labelElapsedTime.Id = 34; this.labelElapsedTime.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconElapsedTime; this.labelElapsedTime.Name = "labelElapsedTime"; + toolTipTitleItem6.Text = "Elapsed Time"; + superToolTip6.Items.Add(toolTipTitleItem6); + this.labelElapsedTime.SuperTip = superToolTip6; this.labelElapsedTime.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // buttonStopScan @@ -1380,24 +1416,31 @@ private void InitializeComponent() { // buttonAutoScroll // this.buttonAutoScroll.ButtonStyle = DevExpress.XtraBars.BarButtonStyle.Check; + this.buttonAutoScroll.Caption = "Auto Scroll Window"; this.buttonAutoScroll.Down = true; this.buttonAutoScroll.Id = 41; this.buttonAutoScroll.ImageOptions.Image = ((System.Drawing.Image)(resources.GetObject("buttonAutoScroll.ImageOptions.Image"))); this.buttonAutoScroll.ImageOptions.LargeImage = ((System.Drawing.Image)(resources.GetObject("buttonAutoScroll.ImageOptions.LargeImage"))); this.buttonAutoScroll.Name = "buttonAutoScroll"; + this.buttonAutoScroll.RibbonStyle = DevExpress.XtraBars.Ribbon.RibbonItemStyles.SmallWithoutText; this.buttonAutoScroll.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // buttonLog // + this.buttonLog.Caption = "Show Log File"; this.buttonLog.Id = 26; this.buttonLog.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconLog; this.buttonLog.Name = "buttonLog"; + this.buttonLog.RibbonStyle = DevExpress.XtraBars.Ribbon.RibbonItemStyles.SmallWithoutText; this.buttonLog.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ButtonLog); // // labelInfo // this.labelInfo.Id = 24; this.labelInfo.Name = "labelInfo"; + toolTipTitleItem7.Text = "Output"; + superToolTip7.Items.Add(toolTipTitleItem7); + this.labelInfo.SuperTip = superToolTip7; // // labelServerInfo // @@ -1405,6 +1448,9 @@ private void InitializeComponent() { this.labelServerInfo.Id = 35; this.labelServerInfo.ImageOptions.Image = global::SQLIndexManager.Properties.Resources.IconInfo; this.labelServerInfo.Name = "labelServerInfo"; + toolTipTitleItem8.Text = "Version"; + superToolTip8.Items.Add(toolTipTitleItem8); + this.labelServerInfo.SuperTip = superToolTip8; this.labelServerInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; // // ribbonControl1 @@ -1458,7 +1504,7 @@ private void InitializeComponent() { this.ribbonControl1.ShowPageHeadersMode = DevExpress.XtraBars.Ribbon.ShowPageHeadersMode.Hide; this.ribbonControl1.ShowQatLocationSelector = false; this.ribbonControl1.ShowToolbarCustomizeItem = false; - this.ribbonControl1.Size = new System.Drawing.Size(1190, 27); + this.ribbonControl1.Size = new System.Drawing.Size(1190, 32); this.ribbonControl1.StatusBar = this.statusBar; this.ribbonControl1.Toolbar.ShowCustomizeItem = false; this.ribbonControl1.ShowCustomizationMenu += new DevExpress.XtraBars.Ribbon.RibbonCustomizationMenuEventHandler(this.GridCustomizationMenu); @@ -1572,7 +1618,8 @@ private void InitializeComponent() { // // toolTipController // - this.toolTipController.Active = false; + this.toolTipController.ToolTipAnchor = DevExpress.Utils.ToolTipAnchor.Object; + this.toolTipController.ToolTipLocation = DevExpress.Utils.ToolTipLocation.TopCenter; // // taskbar // From 1d24f4cfab072c656401fa19d10e562bb350cfa1 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Mon, 28 Jun 2021 07:29:59 +0300 Subject: [PATCH 09/19] Changes in ErrorBox --- Common/Utils.cs | 7 +++++++ Forms/AboutBox.cs | 3 +-- Forms/DatabaseBox.cs | 9 ++++----- Forms/ErrorBox.Designer.cs | 13 ++++++++++--- Forms/ErrorBox.cs | 9 ++++++--- Forms/ErrorBox.resx | 3 +++ Forms/MainBox.cs | 6 ++---- Program.cs | 4 +--- Properties/AssemblyInfo.cs | 4 ++-- 9 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Common/Utils.cs b/Common/Utils.cs index 14c3611..6b177b6 100644 --- a/Common/Utils.cs +++ b/Common/Utils.cs @@ -7,6 +7,13 @@ namespace SQLIndexManager { public static class Utils { + public static void ShowErrorFrom(Exception e, string message = "Error") { + Output.Current.Add($"{message}: {e.Source}", e.Message); + using (ErrorBox errorBox = new ErrorBox(e)) { + errorBox.ShowDialog(); + } + } + public static string Description(this Enum value) { var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false); return da.Length > 0 ? da[0].Description : value.ToString(); diff --git a/Forms/AboutBox.cs b/Forms/AboutBox.cs index 17b45ba..d57c39e 100644 --- a/Forms/AboutBox.cs +++ b/Forms/AboutBox.cs @@ -23,8 +23,7 @@ private void GitHub_HyperlinkClick(object sender, HyperlinkClickEventArgs e) { Process.Start(Resources.GitHubLink); } catch (Exception ex) { - Output.Current.Add($"Error: {ex.Source}", ex.Message); - XtraMessageBox.Show(ex.Message.Replace(". ", "." + Environment.NewLine), ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error); + Utils.ShowErrorFrom(ex); } } diff --git a/Forms/DatabaseBox.cs b/Forms/DatabaseBox.cs index d610bb5..769a13d 100644 --- a/Forms/DatabaseBox.cs +++ b/Forms/DatabaseBox.cs @@ -61,20 +61,19 @@ private void ScanDatabases(object sender, DoWorkEventArgs e) { connection.Open(); try { _disks = QueryEngine.GetDiskInfo(connection); } - catch (Exception ex) { Output.Current.Add("Refresh disk info failed", ex.Message); } + catch (Exception ex) { Utils.ShowErrorFrom(ex, "Refresh disk info failed"); } try { _databases = QueryEngine.GetDatabases(connection); } - catch (Exception ex) { Output.Current.Add("Refresh databases failed", ex.Message); } + catch (Exception ex) { Utils.ShowErrorFrom(ex, "Refresh databases failed"); } if (_databases.Count > 0 && !Settings.ServerInfo.IsAzure) { try { QueryEngine.RefreshDatabaseSize(connection, _databases); } - catch (Exception ex) { Output.Current.Add("Refresh database sizes failed", ex.Message); } + catch (Exception ex) { Utils.ShowErrorFrom(ex, "Refresh database sizes failed"); } } } catch (Exception ex) { - Output.Current.Add("Refresh failed", ex.Message); - XtraMessageBox.Show(ex.Message.Replace(". ", "." + Environment.NewLine), ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error); + Utils.ShowErrorFrom(ex, "Refresh failed"); } finally { connection.Close(); diff --git a/Forms/ErrorBox.Designer.cs b/Forms/ErrorBox.Designer.cs index 2e474a4..e5b6555 100644 --- a/Forms/ErrorBox.Designer.cs +++ b/Forms/ErrorBox.Designer.cs @@ -24,7 +24,9 @@ protected override void Dispose(bool disposing) { /// the contents of this method with the code editor. /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.edError = new DevExpress.XtraEditors.MemoEdit(); + this.defaultLookAndFeel = new DevExpress.LookAndFeel.DefaultLookAndFeel(this.components); ((System.ComponentModel.ISupportInitialize)(this.edError.Properties)).BeginInit(); this.SuspendLayout(); // @@ -40,14 +42,18 @@ private void InitializeComponent() { this.edError.Properties.ReadOnly = true; this.edError.Properties.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.edError.Properties.WordWrap = false; - this.edError.Size = new System.Drawing.Size(597, 333); + this.edError.Size = new System.Drawing.Size(684, 361); this.edError.TabIndex = 0; // + // defaultLookAndFeel + // + this.defaultLookAndFeel.LookAndFeel.SkinName = "Office 2016 Dark"; + // // ErrorBox // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(597, 333); + this.ClientSize = new System.Drawing.Size(684, 361); this.Controls.Add(this.edError); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; @@ -56,7 +62,7 @@ private void InitializeComponent() { this.ShowIcon = false; this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Error"; ((System.ComponentModel.ISupportInitialize)(this.edError.Properties)).EndInit(); this.ResumeLayout(false); @@ -70,5 +76,6 @@ private void BtOk_Click(object sender, System.EventArgs e) { #endregion private DevExpress.XtraEditors.MemoEdit edError; + private DevExpress.LookAndFeel.DefaultLookAndFeel defaultLookAndFeel; } } \ No newline at end of file diff --git a/Forms/ErrorBox.cs b/Forms/ErrorBox.cs index 25a8d32..c3b5b8d 100644 --- a/Forms/ErrorBox.cs +++ b/Forms/ErrorBox.cs @@ -10,11 +10,14 @@ public partial class ErrorBox : XtraForm { public ErrorBox(Exception ex) { InitializeComponent(); + ServerInfo si = null; + try { si = Settings.ServerInfo; } catch { } + edError.Text = - "Application has encountered an unexpected error" + - $"{Environment.NewLine}Please send error detail to {Resources.GitHubLink}" + + $"Application has encountered an unexpected error{Environment.NewLine}" + + $"Please send error detail to {Resources.GitHubLink}{Environment.NewLine}" + + (si == null ? "" : $"{Environment.NewLine}SQL Server: {si}") + $"{Environment.NewLine}Build: {AppInfo.Version}" + - $"{Environment.NewLine}OS: {Environment.OSVersion}" + $"{Environment.NewLine}{Environment.NewLine}{ex.Message}" + $"{Environment.NewLine}{ex.Source}" + $"{Environment.NewLine}{ex.StackTrace}"; diff --git a/Forms/ErrorBox.resx b/Forms/ErrorBox.resx index 1af7de1..644c1ca 100644 --- a/Forms/ErrorBox.resx +++ b/Forms/ErrorBox.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index d066cba..d188739 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using System.Text; -using System.Threading; using System.Windows.Forms; using DevExpress.Data; using DevExpress.Utils; @@ -130,8 +129,7 @@ private void ScanIndexes(object sender, DoWorkEventArgs e) { } if (!ex.Message.Contains("timeout")) { - Output.Current.Add($"Error: {ex.Source}", ex.Message); - XtraMessageBox.Show(ex.Message.Replace(". ", "." + Environment.NewLine), ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error); + Utils.ShowErrorFrom(ex); return; } @@ -906,7 +904,7 @@ private void ButtonLog(object sender, ItemClickEventArgs e) { Process.Start(AppInfo.LogFileName); } catch (Exception ex) { - XtraMessageBox.Show(ex.Message.Replace(". ", "." + Environment.NewLine), ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error); + Utils.ShowErrorFrom(ex); } } diff --git a/Program.cs b/Program.cs index 686aae5..1ba3380 100644 --- a/Program.cs +++ b/Program.cs @@ -48,9 +48,7 @@ static void Main(string[] args) { } private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { - using (ErrorBox errorBox = new ErrorBox(e.Exception)) { - errorBox.ShowDialog(); - } + Utils.ShowErrorFrom(e.Exception); } private static void AttachConsole() { diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index d7d7d59..3c4e301 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -7,5 +7,5 @@ [assembly: AssemblyCopyright("Sergii Syrovatchenko")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("1.0.0.67")] -[assembly: AssemblyFileVersion("1.0.0.67")] +[assembly: AssemblyVersion("1.0.0.68")] +[assembly: AssemblyFileVersion("1.0.0.68")] From 30651c4ed4ec2a506452aa14b9fa0f15abe4e9e1 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sat, 17 Jul 2021 16:43:21 +0300 Subject: [PATCH 10/19] Remove save password functionality --- Console/CmdWorker.cs | 2 +- Forms/ConnectionBox.Designer.cs | 33 +++++++-------------------------- Forms/ConnectionBox.cs | 19 ++++--------------- Forms/MainBox.cs | 11 ++++++++++- Server/Connection.cs | 2 +- Server/Host.cs | 19 ++++++++----------- Settings/Settings.cs | 14 +++++++------- Types/AuthTypes.cs | 4 ++-- 8 files changed, 40 insertions(+), 64 deletions(-) diff --git a/Console/CmdWorker.cs b/Console/CmdWorker.cs index 361a6f6..a43b09e 100644 --- a/Console/CmdWorker.cs +++ b/Console/CmdWorker.cs @@ -19,7 +19,7 @@ public CmdWorker(List args) { case "connection": SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder(cmd.Params[0]); host.Server = sb.DataSource; - host.AuthType = sb.IntegratedSecurity ? AuthTypes.WINDOWS : AuthTypes.SQLSERVER; + host.AuthType = sb.IntegratedSecurity ? AuthTypes.Windows : AuthTypes.Sql; host.User = sb.UserID; if (!string.IsNullOrEmpty(sb.InitialCatalog)) { host.Databases.Add(sb.InitialCatalog); diff --git a/Forms/ConnectionBox.Designer.cs b/Forms/ConnectionBox.Designer.cs index 650ff22..31f7b21 100644 --- a/Forms/ConnectionBox.Designer.cs +++ b/Forms/ConnectionBox.Designer.cs @@ -34,13 +34,11 @@ private void InitializeComponent() { this.label2 = new DevExpress.XtraEditors.LabelControl(); this.label3 = new DevExpress.XtraEditors.LabelControl(); this.label4 = new DevExpress.XtraEditors.LabelControl(); - this.boxSavePassword = new DevExpress.XtraEditors.CheckEdit(); this.progressBar = new DevExpress.XtraEditors.MarqueeProgressBarControl(); ((System.ComponentModel.ISupportInitialize)(this.boxServer.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxAuthType.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxUser.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxPassword.Properties)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.boxSavePassword.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.progressBar.Properties)).BeginInit(); this.SuspendLayout(); // @@ -69,10 +67,8 @@ private void InitializeComponent() { this.boxServer.Location = new System.Drawing.Point(95, 15); this.boxServer.Name = "boxServer"; this.boxServer.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.False; - this.boxServer.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] - { - new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo) - }); + this.boxServer.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { + new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); this.boxServer.Size = new System.Drawing.Size(263, 20); this.boxServer.TabIndex = 1; this.boxServer.SelectedIndexChanged += new System.EventHandler(this.BoxServerSelectionChanged); @@ -83,15 +79,11 @@ private void InitializeComponent() { this.boxAuthType.Location = new System.Drawing.Point(95, 42); this.boxAuthType.Name = "boxAuthType"; this.boxAuthType.Properties.AutoComplete = false; - this.boxAuthType.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] - { - new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo) - }); - this.boxAuthType.Properties.Items.AddRange(new object[] - { - "Windows Authentication", - "SQL Server Authentication" - }); + this.boxAuthType.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { + new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); + this.boxAuthType.Properties.Items.AddRange(new object[] { + "Windows Authentication", + "SQL Server Authentication"}); this.boxAuthType.Properties.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.DisableTextEditor; this.boxAuthType.Size = new System.Drawing.Size(263, 20); this.boxAuthType.TabIndex = 2; @@ -147,14 +139,6 @@ private void InitializeComponent() { this.label4.TabIndex = 13; this.label4.Text = "Password"; // - // boxSavePassword - // - this.boxSavePassword.Location = new System.Drawing.Point(95, 120); - this.boxSavePassword.Name = "boxSavePassword"; - this.boxSavePassword.Properties.Caption = " Save password"; - this.boxSavePassword.Size = new System.Drawing.Size(102, 19); - this.boxSavePassword.TabIndex = 5; - // // progressBar // this.progressBar.EditValue = 0; @@ -176,7 +160,6 @@ private void InitializeComponent() { this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(370, 197); this.Controls.Add(this.progressBar); - this.Controls.Add(this.boxSavePassword); this.Controls.Add(this.label4); this.Controls.Add(this.label3); this.Controls.Add(this.label2); @@ -200,7 +183,6 @@ private void InitializeComponent() { ((System.ComponentModel.ISupportInitialize)(this.boxAuthType.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxUser.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxPassword.Properties)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.boxSavePassword.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.progressBar.Properties)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -219,7 +201,6 @@ private void InitializeComponent() { private DevExpress.XtraEditors.LabelControl label2; private DevExpress.XtraEditors.LabelControl label3; private DevExpress.XtraEditors.LabelControl label4; - private DevExpress.XtraEditors.CheckEdit boxSavePassword; private DevExpress.XtraEditors.MarqueeProgressBarControl progressBar; } } \ No newline at end of file diff --git a/Forms/ConnectionBox.cs b/Forms/ConnectionBox.cs index d776408..3a29df9 100644 --- a/Forms/ConnectionBox.cs +++ b/Forms/ConnectionBox.cs @@ -24,7 +24,6 @@ public Host GetHost() { AuthType = _authType, User = _user, Password = _password, - SavePassword = _savePassword, Databases = _databases, IsUserConnection = true, ServerInfo = _serverInfo @@ -122,11 +121,6 @@ private string _password { set => boxPassword.Text = value; } - private bool _savePassword { - get => boxSavePassword.Checked; - set => boxSavePassword.Checked = value; - } - private List _databases; private ServerInfo _serverInfo; @@ -151,20 +145,17 @@ private void BoxServerSelectionChanged(object sender, EventArgs e) { _authType = host.AuthType; _user = host.User; _password = host.Password; - _savePassword = host.SavePassword; _databases = host.Databases; } } private void BoxAuthTypeSelectionChanged(object sender, EventArgs e) { - bool sqlAuth = (_authType == AuthTypes.SQLSERVER); + bool sqlAuth = (_authType == AuthTypes.Sql); boxUser.Enabled = - boxPassword.Enabled = - boxSavePassword.Enabled = sqlAuth; + boxPassword.Enabled = sqlAuth; if (!sqlAuth) { _user = _password = null; - _savePassword = false; } else { _user = "sa"; @@ -172,7 +163,6 @@ private void BoxAuthTypeSelectionChanged(object sender, EventArgs e) { } private void UpdateControlUsage(bool enabled) { - foreach(Control c in Controls) { c.Enabled = enabled; } @@ -182,14 +172,13 @@ private void UpdateControlUsage(bool enabled) { if (enabled) { boxUser.Enabled = - boxPassword.Enabled = - boxSavePassword.Enabled = (_authType == AuthTypes.SQLSERVER); + boxPassword.Enabled = (_authType == AuthTypes.Sql); } } private void EditValueChanged(object sender, EventArgs e) { buttonOK.Enabled = - !string.IsNullOrEmpty(_server) && !(string.IsNullOrEmpty(_user) && _authType == AuthTypes.SQLSERVER); + !string.IsNullOrEmpty(_server) && !(string.IsNullOrEmpty(_user) && _authType == AuthTypes.Sql); } #endregion diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index d188739..3038e77 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -459,7 +459,7 @@ private void FixIndexesFinish(object sender, RunWorkerCompletedEventArgs e) { #region Dialogs private void MainBox_Shown(object sender, EventArgs e) { - ShowConnectionBox(); + ShowConnectionManagerBox(); } private void ShowDatabaseBox(bool isConnectionChanged) { @@ -483,6 +483,15 @@ private void ShowDatabaseBox(bool isConnectionChanged) { } } + private void ShowConnectionManagerBox() { + using (ConnectionBox form = new ConnectionBox()) { + if (form.ShowDialog(this) == DialogResult.OK) { + Host host = form.GetHost(); + Host lastHost = Settings.Hosts[0]; + } + } + } + private void ShowConnectionBox() { using (ConnectionBox form = new ConnectionBox()) { if (form.ShowDialog(this) == DialogResult.OK) { diff --git a/Server/Connection.cs b/Server/Connection.cs index c136611..514b239 100644 --- a/Server/Connection.cs +++ b/Server/Connection.cs @@ -13,7 +13,7 @@ private static string GetConnectionString(Host host, string database) { InitialCatalog = database ?? "master" }; - if (host.AuthType == AuthTypes.WINDOWS) { + if (host.AuthType == AuthTypes.Windows) { builder.IntegratedSecurity = true; } else { diff --git a/Server/Host.cs b/Server/Host.cs index 4b18769..760b1e3 100644 --- a/Server/Host.cs +++ b/Server/Host.cs @@ -8,31 +8,28 @@ namespace SQLIndexManager { public class Host { [XmlAttribute] - public string Server; + public string Server { get; set; } [XmlAttribute] - public AuthTypes AuthType; + public AuthTypes AuthType { get; set; } [XmlAttribute] - public string User; + public string User { get; set; } [XmlAttribute] - public string Password; + public string Password { get; set; } [XmlElement] - public List Databases; + public List Databases { get; set; } [XmlIgnore] - public bool IsUserConnection; + public bool IsUserConnection { get; set; } [XmlIgnore] - public bool SavePassword; - - [XmlIgnore] - public ServerInfo ServerInfo; + public ServerInfo ServerInfo { get; set; } public Host() { - AuthType = AuthTypes.WINDOWS; + AuthType = AuthTypes.Windows; Databases = new List(); } diff --git a/Settings/Settings.cs b/Settings/Settings.cs index a047825..e20d257 100644 --- a/Settings/Settings.cs +++ b/Settings/Settings.cs @@ -31,7 +31,10 @@ public static Host ActiveHost { public static ServerInfo ServerInfo => _activeHost.ServerInfo; - public static List Hosts => Instance.Hosts; + public static List Hosts { + get => Instance.Hosts; + set => Instance.Hosts = value; + } public static Options Options { get => Instance.Options; @@ -71,10 +74,8 @@ private static void Save() { using (FileStream writer = File.OpenWrite(AppInfo.SettingFileName)) { _current.Hosts.RemoveAll(s => !s.IsUserConnection); _current.Hosts.ForEach(s => { - if (s.AuthType == AuthTypes.SQLSERVER && s.Password != null) { - s.Password = s.SavePassword - ? AES.Encrypt(s.Password) - : null; + if (s.AuthType == AuthTypes.Sql && s.Password != null) { + s.Password = AES.Encrypt(s.Password); } }); @@ -98,9 +99,8 @@ private static void Load() { _current.Hosts.RemoveAll(_ => _.Server == null); _current.Hosts.ForEach(s => { s.IsUserConnection = true; - if (s.AuthType == AuthTypes.SQLSERVER && !string.IsNullOrEmpty(s.Password)) { + if (s.AuthType == AuthTypes.Sql && !string.IsNullOrEmpty(s.Password)) { s.Password = AES.Decrypt(s.Password); - s.SavePassword = true; } }); diff --git a/Types/AuthTypes.cs b/Types/AuthTypes.cs index ce6b818..9c85f7d 100644 --- a/Types/AuthTypes.cs +++ b/Types/AuthTypes.cs @@ -1,8 +1,8 @@ namespace SQLIndexManager { public enum AuthTypes { - WINDOWS = 0, - SQLSERVER = 1 + Windows = 0, + Sql = 1 } } From 8d877748fb859d52dcbe4b50320ebd3842c61c84 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Thu, 7 Oct 2021 14:23:58 +0300 Subject: [PATCH 11/19] Improvements during searching into Server ComboBox control --- Forms/ConnectionBox.Designer.cs | 57 ++++++++++++++++++++------------- Forms/ConnectionBox.cs | 28 ++++++++-------- Forms/MainBox.cs | 11 +------ Properties/AssemblyInfo.cs | 4 +-- 4 files changed, 53 insertions(+), 47 deletions(-) diff --git a/Forms/ConnectionBox.Designer.cs b/Forms/ConnectionBox.Designer.cs index 31f7b21..54ed6cd 100644 --- a/Forms/ConnectionBox.Designer.cs +++ b/Forms/ConnectionBox.Designer.cs @@ -26,7 +26,6 @@ protected override void Dispose(bool disposing) { private void InitializeComponent() { this.buttonCancel = new DevExpress.XtraEditors.SimpleButton(); this.buttonOK = new DevExpress.XtraEditors.SimpleButton(); - this.boxServer = new DevExpress.XtraEditors.ComboBoxEdit(); this.boxAuthType = new DevExpress.XtraEditors.ComboBoxEdit(); this.boxUser = new DevExpress.XtraEditors.TextEdit(); this.boxPassword = new DevExpress.XtraEditors.TextEdit(); @@ -35,45 +34,34 @@ private void InitializeComponent() { this.label3 = new DevExpress.XtraEditors.LabelControl(); this.label4 = new DevExpress.XtraEditors.LabelControl(); this.progressBar = new DevExpress.XtraEditors.MarqueeProgressBarControl(); - ((System.ComponentModel.ISupportInitialize)(this.boxServer.Properties)).BeginInit(); + this.boxServer = new DevExpress.XtraEditors.LookUpEdit(); ((System.ComponentModel.ISupportInitialize)(this.boxAuthType.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxUser.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.boxPassword.Properties)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.progressBar.Properties)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxServer.Properties)).BeginInit(); this.SuspendLayout(); // // buttonCancel // this.buttonCancel.AllowFocus = false; - this.buttonCancel.Location = new System.Drawing.Point(283, 163); + this.buttonCancel.Location = new System.Drawing.Point(283, 134); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(75, 23); - this.buttonCancel.TabIndex = 7; + this.buttonCancel.TabIndex = 6; this.buttonCancel.Text = "Cancel"; this.buttonCancel.Click += new System.EventHandler(this.ButtonCancelClick); // // buttonOK // this.buttonOK.AllowFocus = false; - this.buttonOK.Location = new System.Drawing.Point(202, 163); + this.buttonOK.Location = new System.Drawing.Point(202, 134); this.buttonOK.Name = "buttonOK"; this.buttonOK.Size = new System.Drawing.Size(75, 23); - this.buttonOK.TabIndex = 6; + this.buttonOK.TabIndex = 5; this.buttonOK.Text = "OK"; this.buttonOK.Click += new System.EventHandler(this.ButtonOkClick); // - // boxServer - // - this.boxServer.Location = new System.Drawing.Point(95, 15); - this.boxServer.Name = "boxServer"; - this.boxServer.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.False; - this.boxServer.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { - new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); - this.boxServer.Size = new System.Drawing.Size(263, 20); - this.boxServer.TabIndex = 1; - this.boxServer.SelectedIndexChanged += new System.EventHandler(this.BoxServerSelectionChanged); - this.boxServer.EditValueChanged += new System.EventHandler(this.EditValueChanged); - // // boxAuthType // this.boxAuthType.Location = new System.Drawing.Point(95, 42); @@ -154,11 +142,36 @@ private void InitializeComponent() { this.progressBar.TabIndex = 14; this.progressBar.Visible = false; // + // boxServer + // + this.boxServer.Location = new System.Drawing.Point(95, 15); + this.boxServer.Name = "boxServer"; + this.boxServer.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.False; + this.boxServer.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { + new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); + this.boxServer.Properties.CloseUpKey = new DevExpress.Utils.KeyShortcut(System.Windows.Forms.Keys.F2); + this.boxServer.Properties.Columns.AddRange(new DevExpress.XtraEditors.Controls.LookUpColumnInfo[] { + new DevExpress.XtraEditors.Controls.LookUpColumnInfo("Server", "")}); + this.boxServer.Properties.DisplayMember = "Server"; + this.boxServer.Properties.DropDownRows = 6; + this.boxServer.Properties.NullText = ""; + this.boxServer.Properties.PopupFilterMode = DevExpress.XtraEditors.PopupFilterMode.Contains; + this.boxServer.Properties.PopupSizeable = false; + this.boxServer.Properties.ShowFooter = false; + this.boxServer.Properties.ShowHeader = false; + this.boxServer.Properties.ShowLines = false; + this.boxServer.Properties.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.Standard; + this.boxServer.Properties.ValueMember = "Server"; + this.boxServer.Size = new System.Drawing.Size(263, 20); + this.boxServer.TabIndex = 1; + this.boxServer.EditValueChanged += new System.EventHandler(this.BoxServerSelectionChanged); + this.boxServer.TextChanged += new System.EventHandler(this.EditValueChanged); + // // ConnectionBox // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(370, 197); + this.ClientSize = new System.Drawing.Size(370, 169); this.Controls.Add(this.progressBar); this.Controls.Add(this.label4); this.Controls.Add(this.label3); @@ -167,9 +180,9 @@ private void InitializeComponent() { this.Controls.Add(this.boxPassword); this.Controls.Add(this.boxUser); this.Controls.Add(this.boxAuthType); - this.Controls.Add(this.boxServer); this.Controls.Add(this.buttonCancel); this.Controls.Add(this.buttonOK); + this.Controls.Add(this.boxServer); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.LookAndFeel.SkinName = "Office 2016 Dark"; this.MaximizeBox = false; @@ -179,11 +192,11 @@ private void InitializeComponent() { this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "New Connection"; - ((System.ComponentModel.ISupportInitialize)(this.boxServer.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxAuthType.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxUser.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.boxPassword.Properties)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.progressBar.Properties)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxServer.Properties)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -193,7 +206,6 @@ private void InitializeComponent() { private DevExpress.XtraEditors.SimpleButton buttonCancel; private DevExpress.XtraEditors.SimpleButton buttonOK; - private DevExpress.XtraEditors.ComboBoxEdit boxServer; private DevExpress.XtraEditors.ComboBoxEdit boxAuthType; private DevExpress.XtraEditors.TextEdit boxUser; private DevExpress.XtraEditors.TextEdit boxPassword; @@ -202,5 +214,6 @@ private void InitializeComponent() { private DevExpress.XtraEditors.LabelControl label3; private DevExpress.XtraEditors.LabelControl label4; private DevExpress.XtraEditors.MarqueeProgressBarControl progressBar; + private DevExpress.XtraEditors.LookUpEdit boxServer; } } \ No newline at end of file diff --git a/Forms/ConnectionBox.cs b/Forms/ConnectionBox.cs index 3a29df9..8379475 100644 --- a/Forms/ConnectionBox.cs +++ b/Forms/ConnectionBox.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data.SqlClient; -using System.Linq; using System.Windows.Forms; using DevExpress.XtraEditors; using SQLIndexManager.Properties; @@ -14,8 +13,8 @@ public partial class ConnectionBox : XtraForm { public ConnectionBox() { InitializeComponent(); - boxServer.Properties.Items.AddRange(Settings.Hosts.Select(p => p.Server).ToList()); - boxServer.SelectedIndex = 0; + boxServer.Properties.DataSource = Settings.Hosts; + UpdateServerInfo(0); } public Host GetHost() { @@ -102,8 +101,8 @@ private void CheckConnection(object sender, RunWorkerCompletedEventArgs e) { #region Properties private string _server { - get => boxServer.Text; - set => boxServer.Text = value; + get => (string)boxServer.EditValue; + set => boxServer.EditValue = value; } private AuthTypes _authType { @@ -137,16 +136,19 @@ private void ButtonCancelClick(object sender, EventArgs e) { } private void BoxServerSelectionChanged(object sender, EventArgs e) { - if (boxServer.SelectedIndex != -1) { + UpdateServerInfo(boxServer.ItemIndex); + } - Host host = Settings.Hosts[boxServer.SelectedIndex]; + private void UpdateServerInfo(int index) { + if (index == -1) return; - _server = host.Server; - _authType = host.AuthType; - _user = host.User; - _password = host.Password; - _databases = host.Databases; - } + Host host = Settings.Hosts[index]; + + _server = host.Server; + _authType = host.AuthType; + _user = host.User; + _password = host.Password; + _databases = host.Databases; } private void BoxAuthTypeSelectionChanged(object sender, EventArgs e) { diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index 3038e77..d188739 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -459,7 +459,7 @@ private void FixIndexesFinish(object sender, RunWorkerCompletedEventArgs e) { #region Dialogs private void MainBox_Shown(object sender, EventArgs e) { - ShowConnectionManagerBox(); + ShowConnectionBox(); } private void ShowDatabaseBox(bool isConnectionChanged) { @@ -483,15 +483,6 @@ private void ShowDatabaseBox(bool isConnectionChanged) { } } - private void ShowConnectionManagerBox() { - using (ConnectionBox form = new ConnectionBox()) { - if (form.ShowDialog(this) == DialogResult.OK) { - Host host = form.GetHost(); - Host lastHost = Settings.Hosts[0]; - } - } - } - private void ShowConnectionBox() { using (ConnectionBox form = new ConnectionBox()) { if (form.ShowDialog(this) == DialogResult.OK) { diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 3c4e301..f4106fb 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -7,5 +7,5 @@ [assembly: AssemblyCopyright("Sergii Syrovatchenko")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("1.0.0.68")] -[assembly: AssemblyFileVersion("1.0.0.68")] +[assembly: AssemblyVersion("1.0.0.69")] +[assembly: AssemblyFileVersion("1.0.0.69")] From bcd05621b61c1c28f614b9954c29538db27606d6 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 17 Oct 2021 09:55:32 +0300 Subject: [PATCH 12/19] Bugfix during generation of truncate table/partition statement for columnstore indexes --- Server/Index.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Server/Index.cs b/Server/Index.cs index 7921864..bd75893 100644 --- a/Server/Index.cs +++ b/Server/Index.cs @@ -86,6 +86,13 @@ public string GetQuery() { sql = $"ALTER INDEX {fullIndexName} REORGANIZE PARTITION = {partition}" + $"{(FixType == IndexOp.REORGANIZE_COMPRESS_ALL_ROW_GROUPS ? $"{Environment.NewLine} WITH (COMPRESS_ALL_ROW_GROUPS = ON)" : "")};"; break; + + case IndexOp.TRUNCATE_TABLE: + sql = IsPartitioned + ? $"TRUNCATE TABLE {objectName} WITH (PARTITIONS ({partition}));" + : $"TRUNCATE TABLE {objectName};"; + break; + } } From 7f6ca2272dad48b8e6539b031b43aa7b8b147b47 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 17 Oct 2021 11:02:08 +0300 Subject: [PATCH 13/19] Update StatsSampled/RowsSampled columns during maintenance --- Server/Query.cs | 51 +++++++++++++++++++++++++++++++++++++++++++ Server/QueryEngine.cs | 36 +++++++++++++++--------------- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/Server/Query.cs b/Server/Query.cs index 9e43ae8..6c7037a 100644 --- a/Server/Query.cs +++ b/Server/Query.cs @@ -721,6 +721,55 @@ FROM sys.partitions WITH(NOLOCK) , RowsCount = ISNULL(@RowsCount, 0) , IndexStats = DATEADD(MINUTE, -DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), STATS_DATE({0}, {1})) , DataCompression = @Compression + , StatsSampled = NULL + , RowsSampled = NULL +FROM sys.dm_db_index_physical_stats(@DBID, {0}, {1}, {2}, '{3}') +WHERE [index_level] = 0 + AND [alloc_unit_type_desc] = 'IN_ROW_DATA' +"; + + public const string AfterFixIndexWithStats = @" +DECLARE @UnusedPagesCount BIGINT + , @ReservedPageCount BIGINT + , @RowsCount BIGINT + , @Compression TINYINT + , @DBID INT + , @DBNAME SYSNAME + , @StatsSampled FLOAT + , @RowsSampled BIGINT + +SET @DBNAME = DB_NAME() +SELECT @DBID = [database_id] +FROM sys.databases WITH(NOLOCK) +WHERE [name] = @DBNAME + +SELECT TOP(1) @UnusedPagesCount = [used_page_count] + , @ReservedPageCount = [reserved_page_count] + , @RowsCount = [row_count] +FROM sys.dm_db_partition_stats WITH(NOLOCK) +WHERE [object_id] = {0} + AND [index_id] = {1} + AND [partition_number] = {2} + +SELECT @Compression = [data_compression] +FROM sys.partitions WITH(NOLOCK) +WHERE [object_id] = {0} + AND [index_id] = {1} + AND [partition_number] = {2} + +SELECT TOP(1) @StatsSampled = [rows_sampled] * 100. / NULLIF([rows], 0) + , @RowsSampled = [rows_sampled] +FROM sys.dm_db_stats_properties({0}, {1}) + +SELECT Fragmentation = [avg_fragmentation_in_percent] + , PageSpaceUsed = [avg_page_space_used_in_percent] + , PagesCount = ISNULL(@ReservedPageCount, 0) + , UnusedPagesCount = ISNULL(CASE WHEN ABS(@ReservedPageCount - @UnusedPagesCount) > 32 THEN @ReservedPageCount - @UnusedPagesCount END, 0) + , RowsCount = ISNULL(@RowsCount, 0) + , IndexStats = DATEADD(MINUTE, -DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), STATS_DATE({0}, {1})) + , DataCompression = @Compression + , StatsSampled = @StatsSampled + , RowsSampled = @RowsSampled FROM sys.dm_db_index_physical_stats(@DBID, {0}, {1}, {2}, '{3}') WHERE [index_level] = 0 AND [alloc_unit_type_desc] = 'IN_ROW_DATA' @@ -746,6 +795,8 @@ FROM sys.fn_column_store_row_groups({0}) , RowsCount = ISNULL([rows], 0) , IndexStats = NULL , DataCompression = [data_compression] + , StatsSampled = NULL + , RowsSampled = NULL FROM sys.partitions WITH(NOLOCK) WHERE [object_id] = {0} AND [index_id] = {1} diff --git a/Server/QueryEngine.cs b/Server/QueryEngine.cs index 010c7b4..29625f0 100644 --- a/Server/QueryEngine.cs +++ b/Server/QueryEngine.cs @@ -358,20 +358,23 @@ public static void GetColumnstoreFragmentation(SqlConnection connection, Index i public static string FixIndex(SqlConnection connection, Index ix) { int indexId = ix.FixType == IndexOp.CREATE_COLUMNSTORE_INDEX && ix.IndexType == IndexType.HEAP ? 1 : ix.IndexId; - - string sqlInfo = string.Format(ix.IsColumnstore ? Query.AfterFixColumnstoreIndex : Query.AfterFixIndex, - ix.ObjectId, indexId, ix.PartitionNumber, Settings.Options.ScanMode); - + string sql; string query = ix.GetQuery(); - string sql = ix.FixType == IndexOp.DISABLE_INDEX - || ix.FixType == IndexOp.DROP_INDEX - || ix.FixType == IndexOp.DROP_TABLE - || ix.FixType == IndexOp.CREATE_INDEX - || ix.FixType == IndexOp.UPDATE_STATISTICS_FULL - || ix.FixType == IndexOp.UPDATE_STATISTICS_RESAMPLE - || ix.FixType == IndexOp.UPDATE_STATISTICS_SAMPLE - ? query - : $"{query} \n {sqlInfo}"; + + if (ix.FixType == IndexOp.DISABLE_INDEX || ix.FixType == IndexOp.DROP_INDEX || ix.FixType == IndexOp.DROP_TABLE || ix.FixType == IndexOp.CREATE_INDEX) { + sql = query; + } + else { + string sqlInfo; + if (ix.IsColumnstore) + sqlInfo = Query.AfterFixColumnstoreIndex; + else if (Settings.ServerInfo.IsFullStats && (ix.IndexType == IndexType.CLUSTERED || ix.IndexType == IndexType.NONCLUSTERED) && !ix.IsPartitioned) + sqlInfo = Query.AfterFixIndexWithStats; + else + sqlInfo = Query.AfterFixIndex; + + sql = $"{query} \n {string.Format(sqlInfo, ix.ObjectId, indexId, ix.PartitionNumber, Settings.Options.ScanMode)}"; + } SqlCommand cmd = new SqlCommand(sql, connection) { CommandTimeout = Settings.Options.CommandTimeout }; SqlDataAdapter adapter = new SqlDataAdapter(cmd); @@ -386,10 +389,7 @@ public static string FixIndex(SqlConnection connection, Index ix) { if (string.IsNullOrEmpty(ix.Error)) { try { - if (ix.FixType == IndexOp.UPDATE_STATISTICS_FULL || ix.FixType == IndexOp.UPDATE_STATISTICS_RESAMPLE || ix.FixType == IndexOp.UPDATE_STATISTICS_SAMPLE) { - ix.IndexStats = DateTime.UtcNow; - } - else if (ix.FixType == IndexOp.CREATE_INDEX) { + if (ix.FixType == IndexOp.CREATE_INDEX) { ix.IndexStats = DateTime.UtcNow; ix.Fragmentation = 0; } @@ -411,6 +411,8 @@ public static string FixIndex(SqlConnection connection, Index ix) { ix.RowsCount = row.Field(Resources.RowsCount); ix.DataCompression = ((DataCompression)row.Field(Resources.DataCompression)); ix.IndexStats = row.Field(Resources.IndexStats); + ix.StatsSampled = row.Field(Resources.StatsSampled) ?? ix.StatsSampled; + ix.RowsSampled = row.Field(Resources.RowsSampled) ?? ix.RowsSampled; if (ix.FixType == IndexOp.CREATE_COLUMNSTORE_INDEX) { ix.IndexName = "CCL"; From 0b35b7d6120ca2b272206f6b434890b455c82ef7 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sat, 6 Nov 2021 15:29:45 +0200 Subject: [PATCH 14/19] Ignore UPDATE STATISTICS for already up-to-date stats --- Forms/MainBox.cs | 37 +++++--- Forms/SettingsBox.Designer.cs | 156 +++++++++++++++++++++++++++++++++- Forms/SettingsBox.cs | 14 ++- Forms/SettingsBox.resx | 9 ++ Settings/Options.cs | 22 +++++ 5 files changed, 221 insertions(+), 17 deletions(-) diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index d188739..bc6aaf4 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -216,26 +216,41 @@ private void ScanIndexesFinish(object sender, RunWorkerCompletedEventArgs e) { buttonStopScan.Visibility = BarItemVisibility.Never; - List indexes = _indexes.Where(_ => _.Fragmentation >= (Settings.Options.SkipOperation == IndexOp.IGNORE ? Settings.Options.FirstThreshold : 0) - && _.PagesCount >= Settings.Options.MinIndexSize.PageSize() - && _.PagesCount <= Settings.Options.MaxIndexSize.PageSize()) - .OrderBy(_ => _.Fragmentation < Settings.Options.FirstThreshold - && Settings.Options.SkipOperation != Settings.Options.FirstOperation - ? 3 - : _.Fragmentation < Settings.Options.SecondThreshold - && Settings.Options.FirstOperation != Settings.Options.SecondOperation - ? 2 : 1 ) - .ThenByDescending(_ => (_.Fragmentation + 0.1) * _.PagesCount).ToList(); + var o = Settings.Options; + + List indexes = _indexes.Where(_ => _.Fragmentation >= (o.SkipOperation == IndexOp.IGNORE ? o.FirstThreshold : 0) + && _.PagesCount >= o.MinIndexSize.PageSize() + && _.PagesCount <= o.MaxIndexSize.PageSize()) + .OrderBy(_ => _.Fragmentation < o.FirstThreshold && o.SkipOperation != o.FirstOperation + ? 3 + : _.Fragmentation < o.SecondThreshold && o.FirstOperation != o.SecondOperation + ? 2 : 1 ) + .ThenByDescending(_ => (_.Fragmentation + 0.1) * _.PagesCount).ToList(); QueryEngine.UpdateFixType(indexes); QueryEngine.FindDublicateIndexes(indexes); QueryEngine.FindUnusedIndexes(indexes); + if (o.StatsIgnoreHoursEnabled || o.StatsIgnoreSampledPercentEnabled) { + indexes.RemoveAll(_ => _.IndexStats != null + && ( + _.FixType == IndexOp.UPDATE_STATISTICS_FULL + || _.FixType == IndexOp.UPDATE_STATISTICS_RESAMPLE + || _.FixType == IndexOp.UPDATE_STATISTICS_SAMPLE + ) + && ( + (o.StatsIgnoreHoursEnabled && (DateTime.UtcNow - (DateTime)_.IndexStats).TotalHours < o.StatsIgnoreHours) + || + (o.StatsIgnoreSampledPercentEnabled && _.StatsSampled > o.StatsIgnoreSampledPercent) + ) + ); + } + _ps.Indexes = _ps.IndexesTotal = indexes.Count; _ps.IndexesSize = indexes.Sum(_ => _.PagesCount); _ps.SavedSpace = indexes.Sum(_ => _.UnusedPagesCount); UpdateProgressStats(); - + Output.Current.Add($"Processed: {_indexes.Count}. Fragmented: {_ps.Indexes}{(_ps.Indexes == 0 ? ". No indexes found. Try searching again or change settings..." : string.Empty)}"); grid.DataSource = indexes; diff --git a/Forms/SettingsBox.Designer.cs b/Forms/SettingsBox.Designer.cs index f6845cb..b7faaa3 100644 --- a/Forms/SettingsBox.Designer.cs +++ b/Forms/SettingsBox.Designer.cs @@ -49,6 +49,9 @@ private void InitializeComponent() { System.Windows.Forms.PictureBox pictureBox1; System.Windows.Forms.PictureBox pictureBox3; System.Windows.Forms.PictureBox pictureBox4; + DevExpress.XtraEditors.GroupControl groupControl6; + DevExpress.XtraEditors.LabelControl labelControl4; + DevExpress.XtraEditors.LabelControl labelControl10; this.labelSkipThreshold = new DevExpress.XtraEditors.LabelControl(); this.boxSkipThreshold = new DevExpress.XtraEditors.ComboBoxEdit(); this.boxSecondThreshold = new DevExpress.XtraEditors.ComboBoxEdit(); @@ -93,6 +96,10 @@ private void InitializeComponent() { this.groupControl4 = new DevExpress.XtraEditors.GroupControl(); this.groupControl5 = new DevExpress.XtraEditors.GroupControl(); this.boxShowSettingsWhenConnectionChanged = new DevExpress.XtraEditors.CheckEdit(); + this.boxStatsIgnoreHours = new DevExpress.XtraEditors.SpinEdit(); + this.boxStatsIgnoreSampledPercent = new DevExpress.XtraEditors.SpinEdit(); + this.boxStatsIgnoreHoursEnabled = new DevExpress.XtraEditors.CheckEdit(); + this.boxStatsIgnoreSampledPercentEnabled = new DevExpress.XtraEditors.CheckEdit(); labelControl9 = new DevExpress.XtraEditors.LabelControl(); labelSortInTempDb = new DevExpress.XtraEditors.LabelControl(); labelLobCompaction = new DevExpress.XtraEditors.LabelControl(); @@ -118,6 +125,9 @@ private void InitializeComponent() { pictureBox1 = new System.Windows.Forms.PictureBox(); pictureBox3 = new System.Windows.Forms.PictureBox(); pictureBox4 = new System.Windows.Forms.PictureBox(); + groupControl6 = new DevExpress.XtraEditors.GroupControl(); + labelControl4 = new DevExpress.XtraEditors.LabelControl(); + labelControl10 = new DevExpress.XtraEditors.LabelControl(); ((System.ComponentModel.ISupportInitialize)(groupControl1)).BeginInit(); groupControl1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.boxSkipThreshold.Properties)).BeginInit(); @@ -173,6 +183,12 @@ private void InitializeComponent() { ((System.ComponentModel.ISupportInitialize)(this.groupControl5)).BeginInit(); this.groupControl5.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.boxShowSettingsWhenConnectionChanged.Properties)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(groupControl6)).BeginInit(); + groupControl6.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreHours.Properties)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreSampledPercent.Properties)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreHoursEnabled.Properties)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreSampledPercentEnabled.Properties)).BeginInit(); this.SuspendLayout(); // // labelControl9 @@ -400,7 +416,7 @@ private void InitializeComponent() { groupControl2.Controls.Add(this.boxConnectionTimeout); groupControl2.Controls.Add(labelControl6); groupControl2.Controls.Add(this.boxCommandTimeout); - groupControl2.Location = new System.Drawing.Point(414, 395); + groupControl2.Location = new System.Drawing.Point(414, 482); groupControl2.Name = "groupControl2"; groupControl2.Size = new System.Drawing.Size(303, 81); groupControl2.TabIndex = 14; @@ -1029,7 +1045,7 @@ private void InitializeComponent() { " "}); this.boxExcludeObject.Properties.ShowDropDown = false; this.boxExcludeObject.Properties.ValidateToken += new DevExpress.XtraEditors.TokenEditValidateTokenEventHandler(this.TokenValidate); - this.boxExcludeObject.Size = new System.Drawing.Size(652, 20); + this.boxExcludeObject.Size = new System.Drawing.Size(343, 20); this.boxExcludeObject.TabIndex = 8; // // boxExcludeSchemas @@ -1078,7 +1094,7 @@ private void InitializeComponent() { " "}); this.boxIncludeObject.Properties.ShowDropDown = false; this.boxIncludeObject.Properties.ValidateToken += new DevExpress.XtraEditors.TokenEditValidateTokenEventHandler(this.TokenValidate); - this.boxIncludeObject.Size = new System.Drawing.Size(652, 20); + this.boxIncludeObject.Size = new System.Drawing.Size(343, 20); this.boxIncludeObject.TabIndex = 15; // // groupControl4 @@ -1101,7 +1117,7 @@ private void InitializeComponent() { this.groupControl5.Controls.Add(this.boxExcludeObject); this.groupControl5.Location = new System.Drawing.Point(12, 482); this.groupControl5.Name = "groupControl5"; - this.groupControl5.Size = new System.Drawing.Size(705, 81); + this.groupControl5.Size = new System.Drawing.Size(396, 81); this.groupControl5.TabIndex = 19; this.groupControl5.Text = "Object Filter (schema.table OR table OR %pattern%)"; // @@ -1115,11 +1131,132 @@ private void InitializeComponent() { this.boxShowSettingsWhenConnectionChanged.TabIndex = 15; this.boxShowSettingsWhenConnectionChanged.TabStop = false; // + // groupControl6 + // + groupControl6.Controls.Add(this.boxStatsIgnoreSampledPercentEnabled); + groupControl6.Controls.Add(this.boxStatsIgnoreHoursEnabled); + groupControl6.Controls.Add(labelControl4); + groupControl6.Controls.Add(this.boxStatsIgnoreHours); + groupControl6.Controls.Add(labelControl10); + groupControl6.Controls.Add(this.boxStatsIgnoreSampledPercent); + groupControl6.Location = new System.Drawing.Point(414, 395); + groupControl6.Name = "groupControl6"; + groupControl6.Size = new System.Drawing.Size(303, 81); + groupControl6.TabIndex = 15; + groupControl6.Text = "Ignore Update Statistics"; + // + // labelControl4 + // + labelControl4.Location = new System.Drawing.Point(14, 25); + labelControl4.Name = "labelControl4"; + labelControl4.Size = new System.Drawing.Size(149, 13); + labelControl4.TabIndex = 13; + labelControl4.Text = "LAST_UPDATE_HOURS_AGO <"; + // + // boxStatsIgnoreHours + // + this.boxStatsIgnoreHours.EditValue = new decimal(new int[] { + 24, + 0, + 0, + 0}); + this.boxStatsIgnoreHours.Location = new System.Drawing.Point(200, 22); + this.boxStatsIgnoreHours.Name = "boxStatsIgnoreHours"; + this.boxStatsIgnoreHours.Properties.AllowFocused = false; + this.boxStatsIgnoreHours.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.False; + this.boxStatsIgnoreHours.Properties.Appearance.Options.UseTextOptions = true; + this.boxStatsIgnoreHours.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center; + this.boxStatsIgnoreHours.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { + new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); + this.boxStatsIgnoreHours.Properties.DisplayFormat.FormatString = "n0"; + this.boxStatsIgnoreHours.Properties.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Custom; + this.boxStatsIgnoreHours.Properties.EditFormat.FormatString = "n0"; + this.boxStatsIgnoreHours.Properties.EditFormat.FormatType = DevExpress.Utils.FormatType.Custom; + this.boxStatsIgnoreHours.Properties.IsFloatValue = false; + this.boxStatsIgnoreHours.Properties.Mask.EditMask = "N00"; + this.boxStatsIgnoreHours.Properties.MaxValue = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.boxStatsIgnoreHours.Properties.MinValue = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.boxStatsIgnoreHours.Size = new System.Drawing.Size(88, 20); + this.boxStatsIgnoreHours.TabIndex = 12; + this.boxStatsIgnoreHours.TabStop = false; + // + // labelControl10 + // + labelControl10.Location = new System.Drawing.Point(14, 53); + labelControl10.Name = "labelControl10"; + labelControl10.Size = new System.Drawing.Size(144, 13); + labelControl10.TabIndex = 7; + labelControl10.Text = "STATS_SAMPLED_PERCENT >"; + // + // boxStatsIgnoreSampledPercent + // + this.boxStatsIgnoreSampledPercent.EditValue = new decimal(new int[] { + 95, + 0, + 0, + 0}); + this.boxStatsIgnoreSampledPercent.Location = new System.Drawing.Point(200, 50); + this.boxStatsIgnoreSampledPercent.Name = "boxStatsIgnoreSampledPercent"; + this.boxStatsIgnoreSampledPercent.Properties.AllowFocused = false; + this.boxStatsIgnoreSampledPercent.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.False; + this.boxStatsIgnoreSampledPercent.Properties.Appearance.Options.UseTextOptions = true; + this.boxStatsIgnoreSampledPercent.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center; + this.boxStatsIgnoreSampledPercent.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { + new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)}); + this.boxStatsIgnoreSampledPercent.Properties.DisplayFormat.FormatString = "n0"; + this.boxStatsIgnoreSampledPercent.Properties.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Custom; + this.boxStatsIgnoreSampledPercent.Properties.EditFormat.FormatString = "n0"; + this.boxStatsIgnoreSampledPercent.Properties.EditFormat.FormatType = DevExpress.Utils.FormatType.Custom; + this.boxStatsIgnoreSampledPercent.Properties.IsFloatValue = false; + this.boxStatsIgnoreSampledPercent.Properties.Mask.EditMask = "N00"; + this.boxStatsIgnoreSampledPercent.Properties.MaxValue = new decimal(new int[] { + 99, + 0, + 0, + 0}); + this.boxStatsIgnoreSampledPercent.Properties.MinValue = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.boxStatsIgnoreSampledPercent.Size = new System.Drawing.Size(88, 20); + this.boxStatsIgnoreSampledPercent.TabIndex = 6; + this.boxStatsIgnoreSampledPercent.TabStop = false; + // + // boxStatsIgnoreHoursEnabled + // + this.boxStatsIgnoreHoursEnabled.Location = new System.Drawing.Point(179, 22); + this.boxStatsIgnoreHoursEnabled.Name = "boxStatsIgnoreHoursEnabled"; + this.boxStatsIgnoreHoursEnabled.Properties.AllowFocused = false; + this.boxStatsIgnoreHoursEnabled.Properties.Caption = ""; + this.boxStatsIgnoreHoursEnabled.Size = new System.Drawing.Size(19, 19); + this.boxStatsIgnoreHoursEnabled.TabIndex = 28; + this.boxStatsIgnoreHoursEnabled.TabStop = false; + // + // boxStatsIgnoreSampledPercentEnabled + // + this.boxStatsIgnoreSampledPercentEnabled.Location = new System.Drawing.Point(179, 50); + this.boxStatsIgnoreSampledPercentEnabled.Name = "boxStatsIgnoreSampledPercentEnabled"; + this.boxStatsIgnoreSampledPercentEnabled.Properties.AllowFocused = false; + this.boxStatsIgnoreSampledPercentEnabled.Properties.Caption = ""; + this.boxStatsIgnoreSampledPercentEnabled.Size = new System.Drawing.Size(19, 19); + this.boxStatsIgnoreSampledPercentEnabled.TabIndex = 29; + this.boxStatsIgnoreSampledPercentEnabled.TabStop = false; + // // SettingsBox // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(726, 605); + this.Controls.Add(groupControl6); this.Controls.Add(this.boxShowSettingsWhenConnectionChanged); this.Controls.Add(this.groupControl5); this.Controls.Add(this.groupControl4); @@ -1199,6 +1336,13 @@ private void InitializeComponent() { this.groupControl5.ResumeLayout(false); this.groupControl5.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.boxShowSettingsWhenConnectionChanged.Properties)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(groupControl6)).EndInit(); + groupControl6.ResumeLayout(false); + groupControl6.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreHours.Properties)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreSampledPercent.Properties)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreHoursEnabled.Properties)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.boxStatsIgnoreSampledPercentEnabled.Properties)).EndInit(); this.ResumeLayout(false); } @@ -1249,5 +1393,9 @@ private void InitializeComponent() { private DevExpress.XtraEditors.CheckEdit boxShowSettingsWhenConnectionChanged; private DevExpress.XtraEditors.CheckEdit boxIgnoreHeapWithCompression; private DevExpress.XtraEditors.CheckEdit boxShowOnlyMore1000Rows; + private DevExpress.XtraEditors.SpinEdit boxStatsIgnoreHours; + private DevExpress.XtraEditors.SpinEdit boxStatsIgnoreSampledPercent; + private DevExpress.XtraEditors.CheckEdit boxStatsIgnoreSampledPercentEnabled; + private DevExpress.XtraEditors.CheckEdit boxStatsIgnoreHoursEnabled; } } \ No newline at end of file diff --git a/Forms/SettingsBox.cs b/Forms/SettingsBox.cs index 61e52ed..cf71283 100644 --- a/Forms/SettingsBox.cs +++ b/Forms/SettingsBox.cs @@ -56,14 +56,19 @@ private void UpdateControls(Options o) { boxConnectionTimeout.Value = o.ConnectionTimeout; boxCommandTimeout.Value = o.CommandTimeout; boxWaitAtLowPriority.Checked = o.WaitAtLowPriority; - boxMaxDuration.EditValue = o.MaxDuration; + boxMaxDuration.Value = o.MaxDuration; boxAbortAfterWait.EditValue = o.AbortAfterWait; boxDataCompression.EditValue = o.DataCompression; boxNoRecompute.EditValue = o.NoRecompute; - boxFillFactor.EditValue = o.FillFactor; + boxFillFactor.Value = o.FillFactor; boxScanMode.EditValue = o.ScanMode; boxShowSettingsWhenConnectionChanged.Checked = o.ShowSettingsWhenConnectionChanged; + boxStatsIgnoreHours.Value = o.StatsIgnoreHours; + boxStatsIgnoreHoursEnabled.Checked = o.StatsIgnoreHoursEnabled; + boxStatsIgnoreSampledPercent.Value = o.StatsIgnoreSampledPercent; + boxStatsIgnoreSampledPercentEnabled.Checked = o.StatsIgnoreSampledPercentEnabled; + boxScanHeap.Checked = o.ScanHeap; boxScanClusteredIndex.Checked = o.ScanClusteredIndex; boxScanNonClusteredIndex.Checked = o.ScanNonClusteredIndex; @@ -108,6 +113,11 @@ public Options GetSettings() { ScanMode = boxScanMode.EditValue.ToEnum(), ShowSettingsWhenConnectionChanged = boxShowSettingsWhenConnectionChanged.Checked, + StatsIgnoreHours = (int)boxStatsIgnoreHours.Value, + StatsIgnoreHoursEnabled = boxStatsIgnoreHoursEnabled.Checked, + StatsIgnoreSampledPercent = (int)boxStatsIgnoreSampledPercent.Value, + StatsIgnoreSampledPercentEnabled = boxStatsIgnoreSampledPercentEnabled.Checked, + ScanHeap = boxScanHeap.Checked, ScanClusteredIndex = boxScanClusteredIndex.Checked, ScanNonClusteredIndex = boxScanNonClusteredIndex.Checked, diff --git a/Forms/SettingsBox.resx b/Forms/SettingsBox.resx index 17e71a0..a7196fd 100644 --- a/Forms/SettingsBox.resx +++ b/Forms/SettingsBox.resx @@ -192,4 +192,13 @@ False + + False + + + False + + + False + \ No newline at end of file diff --git a/Settings/Options.cs b/Settings/Options.cs index 72ce4de..6baceac 100644 --- a/Settings/Options.cs +++ b/Settings/Options.cs @@ -20,6 +20,8 @@ public class Options { private int _maxDop; private int _fillFactor; private int _sampleStatsPercent = 100; + private int _statsIgnoreHours = 24; + private int _statsIgnoreSampledPercent = 95; private int _maxDuration = 1; private DataCompression _dataCompression; private List _includeSchemas = new List(); @@ -38,6 +40,8 @@ public Options() { IgnorePermissions = true; IgnoreReadOnlyFL = true; ShowSettingsWhenConnectionChanged = true; + StatsIgnoreHoursEnabled = false; + StatsIgnoreSampledPercentEnabled = false; ScanMode = ScanMode.LIMITED; DataCompression = DataCompression.DEFAULT; @@ -105,6 +109,24 @@ public int SampleStatsPercent { set => _sampleStatsPercent = value.IsBetween(1, 100) ? value : _sampleStatsPercent; } + [XmlAttribute] + public int StatsIgnoreHours { + get => _statsIgnoreHours; + set => _statsIgnoreHours = value.IsBetween(1, 100) ? value : _statsIgnoreHours; + } + + [XmlAttribute] + public bool StatsIgnoreHoursEnabled; + + [XmlAttribute] + public int StatsIgnoreSampledPercent { + get => _statsIgnoreSampledPercent; + set => _statsIgnoreSampledPercent = value.IsBetween(1, 99) ? value : _statsIgnoreSampledPercent; + } + + [XmlAttribute] + public bool StatsIgnoreSampledPercentEnabled; + [XmlAttribute] public int MinIndexSize { get => _minIndexSize; From 402363205727572ca08cd0074fb3a9a7b67671ae Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 14 Nov 2021 11:03:38 +0200 Subject: [PATCH 15/19] Bugfix during filtering with enabled [StatsIgnore]HoursEnabled/SampledPercentEnabled options --- Forms/MainBox.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Forms/MainBox.cs b/Forms/MainBox.cs index bc6aaf4..943df96 100644 --- a/Forms/MainBox.cs +++ b/Forms/MainBox.cs @@ -239,9 +239,17 @@ private void ScanIndexesFinish(object sender, RunWorkerCompletedEventArgs e) { || _.FixType == IndexOp.UPDATE_STATISTICS_SAMPLE ) && ( - (o.StatsIgnoreHoursEnabled && (DateTime.UtcNow - (DateTime)_.IndexStats).TotalHours < o.StatsIgnoreHours) + ( + !o.StatsIgnoreHoursEnabled + || + (o.StatsIgnoreHoursEnabled && (DateTime.UtcNow - (DateTime)_.IndexStats).TotalHours < o.StatsIgnoreHours) + ) || - (o.StatsIgnoreSampledPercentEnabled && _.StatsSampled > o.StatsIgnoreSampledPercent) + ( + !o.StatsIgnoreSampledPercentEnabled + || + (o.StatsIgnoreSampledPercentEnabled && _.StatsSampled > o.StatsIgnoreSampledPercent) + ) ) ); } From df1e3e637bcb04d6b8008a17ed6c9647400fc02d Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sun, 14 Nov 2021 12:24:37 +0200 Subject: [PATCH 16/19] Ignore already fully compressed columnstore indexes --- Server/Query.cs | 4 ++-- Server/QueryEngine.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Server/Query.cs b/Server/Query.cs index 6c7037a..a5fa5f7 100644 --- a/Server/Query.cs +++ b/Server/Query.cs @@ -585,9 +585,9 @@ CROSS APPLY sys.dm_db_index_physical_stats(@DBID, i.ObjectID, i.IndexID, i.Parti FROM ( SELECT IndexID = [index_id] , PartitionNumber = [partition_number] - , PagesCount = SUM([size_in_bytes]) / 8192 + , PagesCount = ISNULL(SUM([size_in_bytes]), 0) / 8192 , UnusedPagesCount = ISNULL(SUM(CASE WHEN [state] = 1 THEN [size_in_bytes] END), 0) / 8192 - , Fragmentation = CAST(ISNULL(SUM(CASE WHEN [state] = 1 THEN [size_in_bytes] END), 0) * 100. / SUM([size_in_bytes]) AS FLOAT) + , Fragmentation = ISNULL(CAST(ISNULL(SUM(CASE WHEN [state] = 1 THEN [size_in_bytes] END), 0) * 100. / SUM([size_in_bytes]) AS FLOAT), 0) FROM sys.fn_column_store_row_groups(@ObjectID) GROUP BY [index_id] , [partition_number] diff --git a/Server/QueryEngine.cs b/Server/QueryEngine.cs index 29625f0..641ab4a 100644 --- a/Server/QueryEngine.cs +++ b/Server/QueryEngine.cs @@ -469,7 +469,7 @@ public static void FindDublicateIndexes(List indexes) { } private static IndexOp CorrectIndexOp(IndexOp op, Index ix) { - if (op == IndexOp.NO_ACTION || op == IndexOp.IGNORE) + if (op == IndexOp.NO_ACTION || op == IndexOp.IGNORE || (ix.IsColumnstore && ix.Fragmentation == 0)) return IndexOp.SKIP; if (ix.IndexType == IndexType.MISSING_INDEX) From 5e1b51c8120fe4cf02fd3e416c99a6f27460b4c8 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Mon, 15 Nov 2021 07:41:56 +0200 Subject: [PATCH 17/19] Disable online rebuild for SQL Server < 2014 to omit "'ONLINE' is not a recognized ALTER INDEX REBUILD PARTITION option" --- Properties/AssemblyInfo.cs | 4 ++-- Server/ServerInfo.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index f4106fb..64b8692 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -7,5 +7,5 @@ [assembly: AssemblyCopyright("Sergii Syrovatchenko")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("1.0.0.69")] -[assembly: AssemblyFileVersion("1.0.0.69")] +[assembly: AssemblyVersion("1.0.0.70")] +[assembly: AssemblyFileVersion("1.0.0.70")] diff --git a/Server/ServerInfo.cs b/Server/ServerInfo.cs index 627b934..b038819 100644 --- a/Server/ServerInfo.cs +++ b/Server/ServerInfo.cs @@ -34,8 +34,9 @@ public override string ToString() => $"SQL Server {ProductVersion} " + || (MajorVersion == ServerVersion.Sql2012 && PatchVersion >= 3000) || MajorVersion >= ServerVersion.Sql2014; + // https://sqlperformance.com/2014/06/sql-indexes/hotfix-sql-2012-rebuilds public bool IsOnlineRebuildAvailable => IsAzure - || (MajorVersion >= ServerVersion.Sql2008 && IsMaxEdititon); + || (MajorVersion >= ServerVersion.Sql2014 && IsMaxEdititon); private string ProductVersion { get { From e0de5ce366897400f9d434cedfba178d32be00e9 Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sat, 20 Nov 2021 09:10:07 +0200 Subject: [PATCH 18/19] Fix 'ONLINE' is not a recognized ALTER INDEX REBUILD PARTITION option --- Server/Index.cs | 4 +++- Server/ServerInfo.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Server/Index.cs b/Server/Index.cs index bd75893..23470aa 100644 --- a/Server/Index.cs +++ b/Server/Index.cs @@ -158,7 +158,9 @@ public string GetQuery() { (!IsAllowCompression ? "" : $"DATA_COMPRESSION = {compression}, ") + - $"ONLINE = {onlineRebuild}, " + + (Settings.ServerInfo.MajorVersion <= ServerVersion.Sql2012 && IsPartitioned // 'ONLINE' is not a recognized ALTER INDEX REBUILD PARTITION option + ? "" + : $"ONLINE = {onlineRebuild}, ") + $"MAXDOP = {Settings.Options.MaxDop});"; break; diff --git a/Server/ServerInfo.cs b/Server/ServerInfo.cs index b038819..11e17bc 100644 --- a/Server/ServerInfo.cs +++ b/Server/ServerInfo.cs @@ -36,7 +36,7 @@ public override string ToString() => $"SQL Server {ProductVersion} " + // https://sqlperformance.com/2014/06/sql-indexes/hotfix-sql-2012-rebuilds public bool IsOnlineRebuildAvailable => IsAzure - || (MajorVersion >= ServerVersion.Sql2014 && IsMaxEdititon); + || (MajorVersion >= ServerVersion.Sql2008 && IsMaxEdititon); private string ProductVersion { get { From c57ab74244296901f1d9d981fdf8b80efffcd09b Mon Sep 17 00:00:00 2001 From: Sergii Syrovatchenko Date: Sat, 20 Nov 2021 09:19:56 +0200 Subject: [PATCH 19/19] Update version for SQL Server 2022 preview --- Properties/AssemblyInfo.cs | 4 ++-- Server/ServerInfo.cs | 4 ++-- Types/ServerVersion.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 64b8692..1ee0fb8 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -7,5 +7,5 @@ [assembly: AssemblyCopyright("Sergii Syrovatchenko")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("1.0.0.70")] -[assembly: AssemblyFileVersion("1.0.0.70")] +[assembly: AssemblyVersion("1.0.0.71")] +[assembly: AssemblyFileVersion("1.0.0.71")] diff --git a/Server/ServerInfo.cs b/Server/ServerInfo.cs index 11e17bc..2918d0f 100644 --- a/Server/ServerInfo.cs +++ b/Server/ServerInfo.cs @@ -55,8 +55,8 @@ private string ProductVersion { return "2017"; case ServerVersion.Sql2019: return "2019"; - case ServerVersion.Sql2021: - return "2021"; + case ServerVersion.Sql2022: + return "2022"; default: return "?"; } diff --git a/Types/ServerVersion.cs b/Types/ServerVersion.cs index 82255e7..52d92a0 100644 --- a/Types/ServerVersion.cs +++ b/Types/ServerVersion.cs @@ -8,7 +8,7 @@ public static class ServerVersion { public const int Sql2016 = 13; public const int Sql2017 = 14; public const int Sql2019 = 15; - public const int Sql2021 = 16; + public const int Sql2022 = 16; } }