Пример #1
0
        public static List <Index> GetIndexes(SqlConnection connection)
        {
            List <int> it = new List <int>();

            if (Settings.Options.ScanHeap)
            {
                it.Add((int)IndexType.Heap);
            }
            if (Settings.Options.ScanClusteredIndex)
            {
                it.Add((int)IndexType.Clustered);
            }
            if (Settings.Options.ScanNonClusteredIndex)
            {
                it.Add((int)IndexType.NonClustered);
            }

            if (Settings.ServerInfo.IsColumnstoreAvailable)
            {
                if (Settings.Options.ScanClusteredColumnstore)
                {
                    it.Add((int)IndexType.ColumnstoreClustered);
                }
                if (Settings.Options.ScanNonClusteredColumnstore)
                {
                    it.Add((int)IndexType.ColumnstoreNonClustered);
                }
            }

            List <Index> indexes = new List <Index>();

            if (it.Count > 0)
            {
                string lob = string.Empty;
                if (Settings.ServerInfo.IsOnlineRebuildAvailable)
                {
                    lob = Settings.ServerInfo.MajorVersion == Server.Sql2008 ? Query.Lob2008 : Query.Lob2012Plus;
                }

                string indexStats = Settings.ServerInfo.IsAzure && connection.Database == Resources.DatamaseMaster
                              ? Query.IndexStatsAzureMaster
                              : Query.IndexStats;

                string indexQuery = Settings.ServerInfo.MajorVersion == Server.Sql2008 ? Query.Index2008 : Query.Index2012Plus;

                List <string> excludeObjectMask = Settings.Options.ExcludeObject.Where(_ => _.Contains("%")).ToList();
                List <string> includeObjectMask = Settings.Options.IncludeObject.Where(_ => _.Contains("%")).ToList();
                List <string> excludeObjectId   = Settings.Options.ExcludeObject.Where(_ => !_.Contains("%")).ToList();
                List <string> includeObjectId   = Settings.Options.IncludeObject.Where(_ => !_.Contains("%")).ToList();

                string excludeList = string.Empty;
                if (Settings.Options.ExcludeSchemas.Count > 0)
                {
                    excludeList += "OR [schema_id] = SCHEMA_ID(N'" + string.Join("') OR [schema_id] = SCHEMA_ID(N'", Settings.Options.ExcludeSchemas) + "') ";
                }

                if (excludeObjectMask.Count > 0)
                {
                    excludeList += "OR [name] LIKE N'" + string.Join("' OR [name] LIKE N'", excludeObjectMask) + "' ";
                }

                if (excludeObjectId.Count > 0)
                {
                    excludeList += "OR [object_id] = OBJECT_ID(N'" + string.Join("') OR [object_id] = OBJECT_ID(N'", excludeObjectId) + "') ";
                }

                string includeListSchemas = Settings.Options.IncludeSchemas.Count > 0
                                      ? "AND ( [schema_id] = SCHEMA_ID(N'" + string.Join("') OR [schema_id] = SCHEMA_ID(N'", Settings.Options.IncludeSchemas) + "') ) "
                                      : string.Empty;

                string includeListObject = string.Empty;
                if (includeObjectMask.Count > 0)
                {
                    includeListObject += "OR [name] LIKE N'" + string.Join("' OR [name] LIKE N'", includeObjectMask) + "' ";
                }

                if (includeObjectId.Count > 0)
                {
                    includeListObject += "OR [object_id] = OBJECT_ID(N'" + string.Join("') OR [object_id] = OBJECT_ID(N'", includeObjectId) + "') ";
                }

                if (!string.IsNullOrEmpty(includeListObject))
                {
                    includeListObject = $"AND ( 1 = 0 {includeListObject})";
                }

                string includeList = string.IsNullOrEmpty(includeListSchemas) && string.IsNullOrEmpty(includeListObject)
                                ? Query.IncludeListEmpty
                                : string.Format(Query.IncludeList, includeListSchemas, includeListObject);

                string ignoreReadOnlyFL  = Settings.Options.IgnoreReadOnlyFL ? "" : "AND fg.[is_read_only] = 0";
                string ignorePermissions = Settings.Options.IgnorePermissions ? "" : "AND PERMISSIONS(i.[object_id]) & 2 = 2";

                string query = string.Format(Query.PreDescribeIndexes,
                                             string.Join(", ", it), excludeList, indexQuery, lob,
                                             indexStats, ignoreReadOnlyFL, ignorePermissions, includeList);

                SqlCommand cmd = new SqlCommand(query, connection)
                {
                    CommandTimeout = Settings.Options.CommandTimeout
                };

                cmd.Parameters.Add(new SqlParameter("@Fragmentation", SqlDbType.Float)
                {
                    Value = Settings.Options.ReorganizeThreshold
                });
                cmd.Parameters.Add(new SqlParameter("@MinIndexSize", SqlDbType.BigInt)
                {
                    Value = Settings.Options.MinIndexSize.PageSize()
                });
                cmd.Parameters.Add(new SqlParameter("@MaxIndexSize", SqlDbType.BigInt)
                {
                    Value = Settings.Options.MaxIndexSize.PageSize()
                });
                cmd.Parameters.Add(new SqlParameter("@PreDescribeSize", SqlDbType.BigInt)
                {
                    Value = Settings.Options.PreDescribeSize.PageSize()
                });

                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                DataSet        data    = new DataSet();
                adapter.Fill(data);

                foreach (DataRow _ in data.Tables[0].AsEnumerable())
                {
                    IndexType indexType       = (IndexType)_.Field <byte>(Resources.IndexType);
                    bool      isOnlineRebuild = Settings.ServerInfo.IsOnlineRebuildAvailable;

                    if (isOnlineRebuild)
                    {
                        if (
                            _.Field <bool>(Resources.IsLobLegacy)
                            ||
                            indexType == IndexType.Heap
                            ||
                            indexType == IndexType.ColumnstoreClustered
                            ||
                            indexType == IndexType.ColumnstoreNonClustered
                            )
                        {
                            isOnlineRebuild = false;
                        }
                        else
                        {
                            isOnlineRebuild =
                                Settings.ServerInfo.MajorVersion > Server.Sql2008
                                ||
                                (Settings.ServerInfo.MajorVersion == Server.Sql2008 && !_.Field <bool>(Resources.IsLob));
                        }
                    }

                    Index index = new Index {
                        DatabaseName         = connection.Database,
                        ObjectId             = _.Field <int>(Resources.ObjectID),
                        IndexId              = _.Field <int>(Resources.IndexID),
                        IndexName            = _.Field <string>(Resources.IndexName),
                        ObjectName           = _.Field <string>(Resources.ObjectName),
                        SchemaName           = _.Field <string>(Resources.SchemaName),
                        PagesCount           = _.Field <long>(Resources.PagesCount),
                        UnusedPagesCount     = _.Field <long>(Resources.UnusedPagesCount),
                        PartitionNumber      = _.Field <int>(Resources.PartitionNumber),
                        RowsCount            = _.Field <long>(Resources.RowsCount),
                        FileGroupName        = _.Field <string>(Resources.FileGroupName),
                        IndexType            = indexType,
                        IsPartitioned        = _.Field <bool>(Resources.IsPartitioned),
                        IsUnique             = _.Field <bool>(Resources.IsUnique),
                        IsPK                 = _.Field <bool>(Resources.IsPK),
                        IsFiltered           = _.Field <bool>(Resources.IsFiltered),
                        FillFactor           = _.Field <int>(Resources.FillFactor),
                        IndexStats           = _.Field <DateTime?>(Resources.IndexStats),
                        TotalWrites          = _.Field <long?>(Resources.TotalWrites),
                        TotalReads           = _.Field <long?>(Resources.TotalReads),
                        TotalSeeks           = _.Field <long?>(Resources.TotalSeeks),
                        TotalScans           = _.Field <long?>(Resources.TotalScans),
                        TotalLookups         = _.Field <long?>(Resources.TotalLookups),
                        LastUsage            = _.Field <DateTime?>(Resources.LastUsage),
                        DataCompression      = (DataCompression)_.Field <byte>(Resources.DataCompression),
                        Fragmentation        = _.Field <double?>(Resources.Fragmentation),
                        IsAllowReorganize    = _.Field <bool>(Resources.IsAllowPageLocks) && indexType != IndexType.Heap,
                        IsAllowOnlineRebuild = isOnlineRebuild,
                        IsAllowCompression   = Settings.ServerInfo.IsCompressionAvailable && !_.Field <bool>(Resources.IsSparse),
                        IndexColumns         = _.Field <string>(Resources.IndexColumns),
                        IncludedColumns      = _.Field <string>(Resources.IncludedColumns)
                    };

                    indexes.Add(index);
                }
            }

            if (Settings.Options.ScanMissingIndex)
            {
                SqlCommand cmd = new SqlCommand(Query.MissingIndex, connection)
                {
                    CommandTimeout = Settings.Options.CommandTimeout
                };

                cmd.Parameters.Add(new SqlParameter("@Fragmentation", SqlDbType.Float)
                {
                    Value = Settings.Options.ReorganizeThreshold
                });
                cmd.Parameters.Add(new SqlParameter("@MinIndexSize", SqlDbType.BigInt)
                {
                    Value = Settings.Options.MinIndexSize.PageSize()
                });
                cmd.Parameters.Add(new SqlParameter("@MaxIndexSize", SqlDbType.BigInt)
                {
                    Value = Settings.Options.MaxIndexSize.PageSize()
                });

                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                DataSet        data    = new DataSet();
                adapter.Fill(data);

                foreach (DataRow _ in data.Tables[0].AsEnumerable())
                {
                    double fragmentation = _.Field <double>(Resources.Fragmentation);
                    string indexCols     = _.Field <string>(Resources.IndexColumns);
                    string objName       = _.Field <string>(Resources.ObjectName);
                    string indexName     = $"IX_{Guid.NewGuid().ToString().Truncate(5)}_{objName}_{indexCols}"
                                           .Replace(",", "_")
                                           .Replace("[", string.Empty)
                                           .Replace("]", string.Empty)
                                           .Replace(" ", string.Empty).Truncate(240);

                    Index index = new Index {
                        DatabaseName    = connection.Database,
                        ObjectId        = _.Field <int>(Resources.ObjectID),
                        IndexName       = indexName,
                        ObjectName      = objName,
                        SchemaName      = _.Field <string>(Resources.SchemaName),
                        PagesCount      = _.Field <long>(Resources.PagesCount),
                        RowsCount       = _.Field <long>(Resources.RowsCount),
                        FileGroupName   = _.Field <string>(Resources.FileGroupName),
                        IndexType       = IndexType.MissingIndex,
                        IndexStats      = _.Field <DateTime?>(Resources.IndexStats),
                        TotalReads      = _.Field <long?>(Resources.TotalReads),
                        TotalSeeks      = _.Field <long?>(Resources.TotalSeeks),
                        TotalScans      = _.Field <long?>(Resources.TotalScans),
                        LastUsage       = _.Field <DateTime?>(Resources.LastUsage),
                        DataCompression = DataCompression.None,
                        Fragmentation   = fragmentation,
                        IndexColumns    = indexCols,
                        IncludedColumns = _.Field <string>(Resources.IncludedColumns)
                    };

                    indexes.Add(index);
                }
            }

            return(indexes);
        }