2010. 6. 4. 01:16

데이터베이스 사이즈

데이터베이스 사이즈 측정

  1. DB파일사이즈
  2.  Estimating the size of Table
  • (Heap 사이즈 혹은 클러스터 인덱스 사이즈) + 넌 클러스터 인덱스 사이즈의 합

  • 사이즈계산법

  • 사이즈 계산법으로 말고 sp_spaceused 에 datasize와 인덱스 사이즈를 보고 테이블 전체 사이즈를 아는것과 다른가?

    • sp_spaceused 프로시저 확인해 보기 : 확인해 보니 복잡하지 않고 윗 부분과 동일한 것 같음

    1.  --=====================================================
    2.  - 테이블 사이즈  
    3. --======================================================

    4. SELECT  

      1.   @reservedpages = SUM (reserved_page_count), 

      2.   @usedpages = SUM (used_page_count), 

      3.   @pages = SUM ( 

      4.    CASE 

      5.     WHEN (index_id < 2) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count) 

      6.     ELSE lob_used_page_count + row_overflow_used_page_count 

      7.    END 

      8.    ), 

      9.   @rowCount = SUM ( 

      10.    CASE 

      11.     WHEN (index_id < 2) THEN row_count 

      12.     ELSE 0 

      13.    END 

      14.    ) 

      15.  FROM sys.dm_db_partition_stats 

      16.  WHERE object_id = @id; 

      17.  

      18. SELECT  

      19.   name = OBJECT_NAME (@id), 

      20.   rows = convert (char(11), @rowCount), 

      21.   reserved = LTRIM (STR (@reservedpages * 8, 15, 0) + ' KB'), 

      22.   data = LTRIM (STR (@pages * 8, 15, 0) + ' KB'), 

      23.   index_size = LTRIM (STR ((CASE WHEN @usedpages > @pages THEN (@usedpages - @pages) ELSE 0 END) * 8, 15, 0) + ' KB'), 

      24.   unused = LTRIM (STR ((CASE WHEN @reservedpages > @usedpages THEN (@reservedpages - @usedpages) ELSE 0 END) * 8, 15, 0) + ' KB')

       

 

 

이 글은 스프링노트에서 작성되었습니다.

'T-SQL' 카테고리의 다른 글

Index::Defrag Script v4.0  (0) 2010.06.15
T_SQL::미 사용 Table  (0) 2010.06.15
T-SQL::Removing Duplication Data  (1) 2010.06.03
T-SQL::DB_Restore_move_to  (0) 2010.06.03
2010. 6. 3. 23:56

T-SQL::Removing Duplication Data

 쉬운것 같으면서도 가끔 PK 생성때 중복 데이터가 있어서 안될 경우.

그게 또 대용량 데이터라면.. 참..  다시 데이터를 넣거나. 아니면 임시에 넣었다가 지우거나 그랬는데..

rowcount 쓰는 법이랑 2005의 row_number()를 이용할 수 있음.

 

Removing Duplicates from a Table in SQL Server
11 February 2009
 

Sometimes, in SQL, it is the routine operations that turn out to be the trickiest for a DBA or developer. The cleaning up, or de-duplication, of data is one of those. András runs through a whole range of  methods and tricks, and ends with a a fascinating technique using CTE, ROW_NUMBER() and DELETE

Only rarely will you need to remove duplicate entries from a table on a production database. The tables in these databases should have a constraint, such as a primary key or unique constraint, to prevent these duplicate entries occurring in the first place. However, last year at SQL Bits 3 in Reading, I asked my audience how many of them needed to remove duplicate rows from a table, and almost eighty percent raised a hand.

How is it that duplicates can get into a properly-designed table?  Most commonly, this is due to changes in the business rules that define what constitutes a duplicate, especially after the merging of two different systems.  In this article, I will look at some ways of removing duplicates from tables in SQL Server 2000 and later versions, and at some of the problems that may arise.

Checking for Duplicates

On any version of SQL Server, you can identify duplicates using a simple query, with GROUP BY and HAVING, as follows:

DECLARE @table TABLE (data VARCHAR(20))

INSERT INTO @table VALUES ('not duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('duplicate row')

 

SELECT  data

      , COUNT(data) nr

FROM    @table

GROUP BY data

HAVING  COUNT(data) > 1

The result indicates that there are two occurrences of the row containing the “duplicate row” text:

data                 nr

-------------------- -----------

duplicate row        2

Removing Duplicate Rows in SQL Server

The following sections present a variety of techniques for removing duplicates from SQL Server database tables, depending on the nature of the table design.

Tables with no primary key

When you have duplicates in a table that has no primary key defined, and you are using an older version of SQL Server, such as SQL Server 2000, you do not have an easy way to identify a single row. Therefore, you cannot simply delete this row by specifying a WHERE clause in a DELETE statement.

You can, however, use the SET ROWCOUNT 1 command, which will restrict the subsequent DELETE statement to removing only one row. For example:

DECLARE @table TABLE (data VARCHAR(20))

INSERT INTO @table VALUES ('not duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('duplicate row')

 

SET ROWCOUNT 1

DELETE FROM @table WHERE data = 'duplicate row'

SET ROWCOUNT 0

In the above example, only one row is deleted. Consequently, there will be one remaining row with the content “duplicate row”. If you have more than one duplicate of a particular row, you would simply adjust the ROWCOUNT accordingly. Note that after the delete, you should reset the ROWCOUNT to 0 so that subsequent queries are not affected.

To remove all duplicates in a single pass, the following code will work, but is likely to be horrendously slow if there are a large number of duplicates and table rows:

DECLARE @table TABLE (data VARCHAR(20))

INSERT INTO @table VALUES ('not duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('duplicate row')

 

SET NOCOUNT ON

SET ROWCOUNT 1

WHILE 1 = 1

   BEGIN

      DELETE   FROM @table

      WHERE    data IN (SELECT  data

                               FROM    @table

                               GROUP BY data

                               HAVING  COUNT(*) > 1)

      IF @@Rowcount = 0

         BREAK ;

   END

SET ROWCOUNT 0

When cleaning up a table that has a large number of duplicate rows, a better approach is to select just a distinct list of the duplicates, delete all occurrences of those duplicate entries from the original and then insert the list into the original table.

DECLARE @table TABLE(data VARCHAR(20))

INSERT INTO @table VALUES ('not duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('second duplicate row')

INSERT INTO @table VALUES ('second duplicate row')

 

SELECT   data

INTO     #duplicates

FROM     @table

GROUP BY data

HAVING   COUNT(*) > 1

 

-- delete all rows that are duplicated

DELETE   FROM @table

FROM     @table o INNER JOIN #duplicates d

         ON d.data = o.data

 

-- insert one row for every duplicate set

INSERT   INTO @table(data)

         SELECT   data

         FROM     #duplicates

As a variation of this technique, you could select all the data, without duplicates, into a new table, delete the old table, and then rename the new table to match the name of the original table:

CREATE TABLE duplicateTable3(data VARCHAR(20))

INSERT INTO duplicateTable3 VALUES ('not duplicate row')

INSERT INTO duplicateTable3 VALUES ('duplicate row')

INSERT INTO duplicateTable3 VALUES ('duplicate row')

INSERT INTO duplicateTable3 VALUES ('second duplicate row')

INSERT INTO duplicateTable3 VALUES ('second duplicate row')

 

SELECT DISTINCT data

INTO    tempTable

FROM    duplicateTable3

GO

TRUNCATE TABLE duplicateTable3

DROP TABLE duplicateTable3

exec sp_rename 'tempTable', 'duplicateTable3'

In this solution, the SELECT DISTINCT will select all the rows from our table except for the duplicates. These rows are immediately inserted into a table named tempTable. This is a temporary table in the sense that we will use it to temporarily store the unique rows. However, it is not a true temporary table (i.e. one that lives in the temporary database), because we need the table to exist in the current database, so that it can later be renamed, using sp_Rename.

The sp_Rename command is an absolutely horrible way of renaming textual objects, such as stored procedures, because it does not update all the system tables consistently. However, it works well for non-textual schema objects, such as tables.

Note that this solution is usually used on table that has no primary key. If there is a key, and there  are foreign keys referencing the rows that  are identified as being  duplicates, then the foreign key constraints need to be dropped and re-created again during the table swap.

Tables with a primary key, but no foreign key constraints

If your table has a primary key, but no foreign key constraints, then the following solution offers a way to remove duplicates that is much quicker, as it entails less iteration:

DECLARE @table TABLE(

      id INT IDENTITY(1, 1)

    , data VARCHAR(20)

    )

INSERT INTO @table VALUES ('not duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('duplicate row')

 

WHILE 1 = 1

   BEGIN

      DELETE   FROM @table

      WHERE    id IN (SELECT   MAX(id)

                        FROM     @table

                        GROUP BY data

                        HAVING   COUNT(*) > 1)

      IF @@Rowcount = 0

         BREAK ;

   END

Unfortunately, this sort of technique does not scale well.

If your table has a reliable primary key, for example one that has an assigned a value that can be used in a comparison, such as a numeric value in a column with the IDENTITY property enabled, then the following approach is probably the neatest and best. Essentially, it deletes all the duplicates except for the one with the highest value for the primary key. If a table has a unique column such as a number or integer, that will reliably return just one value with  MAX() or MIN(), then you can use this technique  to identify the chosen survivor of the group of duplicates.

DECLARE @table TABLE (

      id INT IDENTITY(1, 1)

    , data VARCHAR(20)

    )

INSERT INTO @table VALUES ('not duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('duplicate row')

INSERT INTO @table VALUES ('second duplicate row')

INSERT INTO @table VALUES ('second duplicate row')

 

 

DELETE  FROM @table

FROM    @table o

        INNER JOIN ( SELECT data

                     FROM   @table

                     GROUP BY data

                     HAVING COUNT(*) > 1

                   ) f ON o.data = f.data

        LEFT OUTER JOIN ( SELECT    [id] = MAX(id)

                          FROM      @table

                          GROUP BY  data

                          HAVING    COUNT(*) > 1

                        ) g ON o.id = g.id

WHERE   g.id IS NULL

This can be simplified even further, though the logic is rather harder to follow.

DELETE   FROM f

FROM     @table AS f INNER JOIN @table AS g

         ON g.data = f.data

              AND f.id < g.id

Tables that are referenced by a Foreign Key

If you've you’ve set up your constraints properly then you will be unable to delete duplicate rows from a table that is referenced by another table, using the above techniques unless you have specified cascading deletes in the foreign key constraints.

You can alter existing foreign key constraints by adding a cascading delete on the foreign key constraint. This means that rows in other tables that refer to the duplicate row via a foreign key constraint will be deleted.  Because you will lose the referenced data as well as the duplicate, you are more likely to wish to save the duplicate data in its entirety first in a holding table.  When you are dealing with real data, you are likely to need to identify the duplicate rows that are being referred to, and delete the duplicates that are not referenced, or merge duplicates and update the references. This task will probably have to be done manually in order to ensure data integrity.

Tables with columns that cannot have a UNIQUE constraint

Sometimes, of course, you may have columns on which you cannot define a unique constraint, or you cannot even use the DISTINCT keyword. Large object types, like NTEXT, TEXT and IMAGE in SQL Server 2000 are good examples of this.  These are data types that cannot be compared, and so the above solutions would not work.

In these situations, you will need to add an extra column to the table that you could use as a surrogate key. Such a surrogate key is not derived from the application data. Its value may be automatically generated, similarly to the identity columns in our previous examples. Unfortunately, in SQL Server, you cannot add an identity column to a table as part of the ALTER TABLE command. The only way to add such a column is to rebuild the table, using SELECT INTO and the IDENTITY() function, as follows:

CREATE TABLE duplicateTable4 (data NTEXT)

INSERT INTO duplicateTable4 VALUES ('not duplicate row')

INSERT INTO duplicateTable4 VALUES ('duplicate row')

INSERT INTO duplicateTable4 VALUES ('duplicate row')

INSERT INTO duplicateTable4 VALUES ('second duplicate row')

INSERT INTO duplicateTable4 VALUES ('second duplicate row')

 

 

SELECT  IDENTITY( INT, 1,1 ) AS id,

        data

INTO    duplicateTable4_Copy

FROM    duplicateTable4

The above will create the duplicateTable4_Copy table. This table will have an identity column named id, which will already have unique numeric values set. Note that although we are creating an Identity column, uniqueness is not enforced in this case; you will need to add a unique index or define the id column as a primary key.

Using a cursor

People with application development background would consider using a cursor to try to eliminate duplicates. The basic idea is to order the contents of the table, iterate through the ordered rows, and check if the current row is equal to the previous row. If it does, then delete the row. This solution could look like the following in T-SQL:

CREATE TABLE duplicateTable5 (data varchar(30))

INSERT INTO duplicateTable5 VALUES ('not duplicate row')

INSERT INTO duplicateTable5 VALUES ('duplicate row')

INSERT INTO duplicateTable5 VALUES ('duplicate row')

INSERT INTO duplicateTable5 VALUES ('second duplicate row')

INSERT INTO duplicateTable5 VALUES ('second duplicate row')

DECLARE @data VARCHAR(30),

    @previousData VARCHAR(30)

DECLARE cursor1 CURSOR SCROLL_LOCKS

    FOR SELECT  data

        FROM    duplicateTable5

        ORDER BY data

    FOR UPDATE

OPEN cursor1

 

FETCH NEXT FROM cursor1 INTO @data

WHILE @@FETCH_STATUS = 0

    BEGIN

          IF @previousData = @data

              DELETE  FROM duplicateTable5

              WHERE CURRENT OF cursor1

                 

          SET @previousData = @data

          FETCH NEXT FROM cursor1 INTO @data

    END

CLOSE cursor1

DEALLOCATE cursor1

The above script will not work, because once you apply the ORDER BY clause in the cursor declaration the cursor will become read-only. If you remove the ORDER BY clause, then there will be no guarantee that the rows will be in order, and checking two subsequent rows would no longer be sufficient to identify duplicates. Interestingly, since the above example creates a small table where all the rows fit onto a single database page and duplicate rows are inserted in groups, removing the ORDER BY clause does make the cursor solution work. It will fail, however, with any table that is larger and has seen some modifications.

New Techniques for Removing Duplicate Rows in SQL Server 2005

SQL Server 2005 has introduced the row_number() function, which provides an alternative means of identifying duplicates. Rewriting the first example, for tables with no primary key, we can now assign a row number to each row in a duplicate group, with a command such as:

DECLARE  @duplicateTable4 TABLE (data VARCHAR(20))

INSERT INTO @duplicateTable4 VALUES ('not duplicate row')

INSERT INTO @duplicateTable4 VALUES ('duplicate row')

INSERT INTO @duplicateTable4 VALUES ('duplicate row')

INSERT INTO @duplicateTable4 VALUES ('second duplicate row')

INSERT INTO @duplicateTable4 VALUES ('second duplicate row')

 

SELECT  data

      , row_number() OVER ( PARTITION BY data ORDER BY data ) AS nr

FROM    @duplicateTable4

The result will show:

data                 nr

-------------------- --------------------

duplicate row        1

duplicate row        2

not duplicate row    1

second duplicate row 1

second duplicate row 2

In the above example, we specify an ordering and partitioning for the row_number() function. Note that the row_number() is a ranking window function, therefore the ORDER BY and the PARTITION BY in the OVER clause are used only to determine the value for the nr column, and they do not affect the row order of the query. Also, while the above is similar to our previous GROUP BY clause, there is a big difference concerning the returned rows. With GROUP BY you must use an aggregate on the columns that are not listed after the GROUP BY. With the OVER clause there is no such restriction, and you can get access to the individual rows in the groups specified by the PARTITION BY clause. This gives us access to the individual duplicate rows, so we can get not only the number of occurrences, but also a sequence number for the individual duplicates. To filter out the duplicate rows only, we could just put the above query into a CTE or a subquery. The CTE approach is as follows:

DECLARE  @duplicateTable4 TABLE (data VARCHAR(20))

INSERT INTO @duplicateTable4 VALUES ('not duplicate row')

INSERT INTO @duplicateTable4 VALUES ('duplicate row')

INSERT INTO @duplicateTable4 VALUES ('duplicate row')

INSERT INTO @duplicateTable4 VALUES ('second duplicate row')

INSERT INTO @duplicateTable4 VALUES ('second duplicate row')

;

WITH    numbered

          AS ( SELECT   data

                      , row_number() OVER ( PARTITION BY data ORDER BY data ) AS nr

               FROM     @duplicateTable4

             )

    SELECT  data

    FROM    numbered

    WHERE   nr > 1

This is not really any different from what we could do on SQL Server 2000.  However, here comes an absolutely amazing feature in SQL Server 2005 and later: We can refer to, and identify, a duplicate row based on the row_number() column and then, with the above CTE expression, we can use a DELETE statement instead of a SELECT, and directly remove the duplicate entries from our table.

We can demonstrate this technique with the following example:

DECLARE  @duplicateTable4 TABLE (data VARCHAR(20))

INSERT INTO @duplicateTable4 VALUES ('not duplicate row')

INSERT INTO @duplicateTable4 VALUES ('duplicate row')

INSERT INTO @duplicateTable4 VALUES ('duplicate row')

INSERT INTO @duplicateTable4 VALUES ('second duplicate row')

INSERT INTO @duplicateTable4 VALUES ('second duplicate row')

;

WITH    numbered

          AS ( SELECT   data

                      , row_number() OVER ( PARTITION BY data ORDER BY data ) AS nr

               FROM     @duplicateTable4

             )

    DELETE  FROM numbered

    WHERE   nr > 1

This solution will even work with large objects, if you stick to the new large object types introduced in SQL Server 2005: i.e. use VARCHAR(MAX) instead of TEXT, NVARCHAR(MAX) instead of NTEXT, and VARBINARY(MAX) instead of IMAGE. These new types are comparable to the deprecated TEXT, NTEXT and IMAGE, and they have the advantage that you will be able to use them with both DISTINCT and row_number().

 I find this last solution, using CTE, ROW_NUMBER() and DELETE, fascinating. Partly because now we can identify rows in a table when there is no other alternative way of doing it, and partly because it is a solution to a problem that should not, in theory, exist at all since production tables will have a unique constraint or a primary key to prevent duplicates getting into the table in the first place.



This article has been viewed 9208 times. 

이 글은 스프링노트에서 작성되었습니다.

'T-SQL' 카테고리의 다른 글

T_SQL::미 사용 Table  (0) 2010.06.15
데이터베이스 사이즈  (0) 2010.06.04
T-SQL::DB_Restore_move_to  (0) 2010.06.03
T-SQL::Convert hex value to String 32bit  (0) 2010.06.03
2010. 6. 3. 23:56

T-SQL::DB_Restore_move_to

  1.  --=============================================================
  2. -- 장비 이동하거나 DB 복원시 파일을 다른 디렉토리로 보관해야할때
  3. -- 파일들이 많은 DB의 경우 일일이 변경하기 어려움이 있어서 원본 기준으로 복원스크립트 생성하고
  4. -- 디렉토리 경로와 백업 파일 경로만 넣어주면 되게끔 생성 한다.
  5. --==============================================================
  6.  

  7. SET NOCOUNT ON

  8. DECLARE @sql            nvarchar(max)

  9. DECLARE @sql_move       nvarchar(3000)

  10. DECLARE @move           nvarchar(200)

  11. DECLARE @backup_type    char(1)

  12. DECLARE @name           sysname

  13. SET @backup_type = 'L' --N

  14. SET @sql_move = ''

  15. DECLARE cur_restore CURSOR FOR

  16.     SELECT name FROM sys.databases WHERE database_id > 4 and NAME != 'LiteSpeedLocal' and state = 0

  17.     ORDER BY name

  18.  

  19. OPEN cur_restore

  20. FETCH NEXT FROM cur_restore

  21. INTO @name

  22.  

  23. WHILE @@FETCH_STATUS = 0

  24. BEGIN

  25.     SET @sql = NULL
        SET @sql_move = ''

  26.     IF @backup_type = 'L'

  27.     BEGIN

  28.         SET @sql = 'exec master.dbo.xp_restore_database' + char(13)

  29.                    + '@database = ''' + @name + '''' + char(13)

  30.                    + ',@filename = ''''' + char(13)

  31.                    + ',@filenumber = 1' + char(13)

  32.                    + ',@with = ''REPLACE''' + char(13)

  33.                    + ',@with = ''NORECOVERY''' + char(13)

  34.  

  35.  

  36.         DECLARE cur_move CURSOR FOR

  37.                 SELECT ',@with = ''MOVE ''''' +

  38.                             name + ''''' TO N''''' +

  39.                             filename + ''''''' '

  40.                 FROM sys.sysaltfiles  WHERE dbid = db_id(@name)

  41.                 ORDER BY fileid

  42.         OPEN cur_move

  43.         FETCH NEXT FROM cur_move

  44.         INTO @move

  45.  

  46.         WHILE @@FETCH_STATUS = 0

  47.         BEGIN

  48.             SET @sql_move = @sql_move + @move + char(13)

  49.            

  50.             FETCH NEXT FROM cur_move

  51.             INTO @move

  52.         END

  53.         CLOSE cur_move

  54.         DEALLOCATE cur_move

  55.  

  56.   

  57.     END

  58.     ELSE IF @backup_type = 'N'

  59.     BEGIN

  60.         SET @sql = 'RESTORE DATABASE ' + @name + char(13)

  61.                  + 'FROM DISK =''''' + char(13)

  62.                  + 'WITH NORECOVERY' + char(13)

  63.  

  64.         DECLARE cur_move CURSOR FOR

  65.                 SELECT ',MOVE ''' + name + ''' TO  ''' + filename + ''''

  66.                 FROM sys.sysaltfiles  WHERE dbid = db_id(@name)

  67.                 ORDER BY fileid

  68.         OPEN cur_move

  69.         FETCH NEXT FROM cur_move

  70.         INTO @move

  71.  

  72.         WHILE @@FETCH_STATUS = 0

  73.         BEGIN

  74.             SET @sql_move = @sql_move + @move + char(13)

  75.            

  76.             FETCH NEXT FROM cur_move

  77.             INTO @move

  78.         END

  79.         CLOSE cur_move

  80.         DEALLOCATE cur_move

  81.     END

  82.  

  83.     SET @sql = @sql + @sql_move + char(13)

  84.  

  85.     print @sql

  86.  

  87.     FETCH NEXT FROM cur_restore

  88.     INTO @name

  89. END

  90.  

  91. CLOSE cur_restore

  92. DEALLOCATE cur_restore

  93.  

이 글은 스프링노트에서 작성되었습니다.

'T-SQL' 카테고리의 다른 글

데이터베이스 사이즈  (0) 2010.06.04
T-SQL::Removing Duplication Data  (1) 2010.06.03
T-SQL::Convert hex value to String 32bit  (0) 2010.06.03
T_SQL::CONSTRAINT조사  (1) 2010.06.03
2010. 6. 3. 23:55

T-SQL::Convert hex value to String 32bit

 Convert Hex value to Signed 32-bit int

 

  1. /* ======================================================================== *
     *   Function Name:    fnHexToInt                                           *
     *                                                                          *
     * -- Description --------------------------------------------------------- *
     * Convert, up to 8 nibbles, hex string ('FFFFFFFF'...'00000000')           *
     *      to                                                                  *
     *  Signed 32-bit int (-2147483648..2147483647).                            *
     * -- History ------------------------------------------------------------- *
     * 1.0.0 28.Oct.2001, Ofer Bester                                           *
     * ======================================================================== */
    PRINT '* CREATE FUNCTION: fnHexToInt, Ver. 1.0.0 (28.Oct.2001).'
    SETUSER 'dbo'
    go
  2. IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'fnHexToInt' AND type IN ('FN', 'IF', 'TF'))
    BEGIN
        PRINT '  + DROP FUNCTION dbo.fnHexToInt.'
        DROP FUNCTION dbo.fnHexToInt
    END
    PRINT '  + CREATE FUNCTION dbo.fnHexToInt.'
    go
  3. CREATE FUNCTION dbo.fnHexToInt (@Hex varchar(8))
    RETURNS int
    -- Ver. 1.0.0 28.Oct.2001, Ofer Bester
    AS BEGIN
        DECLARE @i      tinyint,
                @Nibble tinyint,
                @ch     char(1),
                @Result int
  4.     SET @i      = 1                                                     -- Init nibble counter
        SET @Result = 0                                                     -- Init output parameter
  5.     SET @Hex     = UPPER( LTRIM( RTRIM( @Hex ) ) )                      -- Convert to uppercase
  6.     WHILE (@i <= LEN(@Hex))
        BEGIN
            SET @ch = SUBSTRING(@Hex, @i, 1)
  7.         IF      (@ch >= '0' AND @ch <= '9') SET @Nibble = ASCII(@ch) - ASCII('0')
            ELSE IF (@ch >= 'A' AND @ch <= 'F') SET @Nibble = ASCII(@ch) - ASCII('A') +10
            ELSE RETURN NULL
  8.         IF( @Result > 0x7FFFFFF)                                        -- 134217727 = 0x7FFFFFF
            BEGIN
                SET @Result = @Result & 0x7FFFFFF                           -- Set MSB, of 7 nibbles, OFF
                SET @Result = @Result * 16 + @Nibble +0x80000000            -- Shift left 4Bits, Add last nibble and convert to negetive number.
            END
            ELSE BEGIN
               SET @Result = @Result *16 +@Nibble                           -- Shift left 4Bits, Add nibble.
            END
  9.         SET @i = @i +1                                                  -- Next nibble.
        END -- While
  10.     RETURN ( @Result )
    END -- Function
    go
  11. -- Check create result -------------------------------------------------------
    IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'fnHexToInt' AND type IN ('FN', 'IF', 'TF'))
    BEGIN
        PRINT 'DONE (CREATE FUNCTION: fnHexToInt).'
    END
    ELSE BEGIN
        PRINT '****** FAILES (CREATE FUNCTION: fnHexToInt) ******'
    END
    PRINT ''
    go
  12. SETUSER
    go

이 글은 스프링노트에서 작성되었습니다.

'T-SQL' 카테고리의 다른 글

T-SQL::Removing Duplication Data  (1) 2010.06.03
T-SQL::DB_Restore_move_to  (0) 2010.06.03
T_SQL::CONSTRAINT조사  (1) 2010.06.03
SQL Server 2005 and 2008 Ranking Functions  (0) 2010.04.05
2010. 6. 3. 23:55

T_SQL::CONSTRAINT조사

CONSTRAINT 조사

 

  1. select * from sys.default_constraints 
  2. select * from sys.key_constraints 
  3. select * from sys.check_constraints 

  4. --=================
  5. -- 2005용
  6. --=================
  7. -- FK
  8. SELECT  object_name(fk.constraint_object_id) AS fk_name, 
  9.     fk.constraint_column_id AS fk_clolum,
  10.     object_name(fk.parent_object_id) AS parent_name,
  11.     (select name from sys.columns where object_id =  fk.parent_object_id and column_id = fk.parent_column_id) as parent_column,
  12.     object_name(fk.referenced_object_id) AS referenced_name,
  13.     (select name from sys.columns where object_id =  fk.referenced_object_id and column_id = fk.referenced_column_id) as referenced_column
  14. FROM sys.foreign_key_columns  as fk
  15. WHERE fk.parent_object_id  = object_id('<@table_name, @sysname,@table_name>') 
  16.         or  fk.referenced_object_id = object_id('<@table_name, @sysname,@table_name>')

  17. -- DEFAULT
  18. SELECT object_name(parent_object_id) as table_name,
  19.        name,
  20.        (select name from sys.columns where object_id =  df.parent_object_id and column_id = df.parent_column_id) as column_name, 
  21.        definition
  22. FROM sys.default_constraints   as df
  23. WHERE object_name(parent_object_id) = object_id('<@table_name, @sysname,@table_name>')

  24. -- DEFAULT
  25. SELECT
  26.     object_name(parent_object_id) as table_name,
  27.        name,
  28.        (select name from sys.columns where object_id =  ck.parent_object_id and column_id = ck.parent_column_id) as column_name, 
  29.        definition
  30. FROM sys.check_constraints  as ck
  31. WHERE object_name(parent_object_id) = object_id('<@table_name, @sysname,@table_name>')



  32. --=================
  33. -- 2000용
  34. --=================
  35. --FK
  36. select object_name(fkeyid) , object_name(constid),object_name(rkeyid)  
  37. from sys.sysforeignkeys where fkeyid = object_id ('<@table_name, @sysname,@table_name>')


  38. select object_name(id), object_name(constid) ,status from sys.sysconstraints  
  39. where status&5 = 1 --FK 
  40. where constid  = object_id('<@table_name, @sysname,@table_name>')
  41. order by object_name(constid)



  42. --=========================== 
  43. -- DROP
  44. --===========================
  45. -- FK 2005용
  46. SELECT 'ALTER TABLE ' + bject_name(fk.parent_object_id) + ' DROP CONSTRAINT ' +  object_name(fk.constraint_object_id)
  47. FROM sys.foreign_key_columns
  48. WHERE fk.parent_object_id  = object_id('<@table_name, @sysname,@table_name>') 

  49. -- DEFULT 2005용
  50. SELECT 'ALTER TBLE ' + object_name(parent_object_id)  + ' DROP CONSTRAINT ' + name
  51. FROM sys.default_constraints 
  52. WHERE object_name(parent_object_id) = object_id('<@table_name, @sysname,@table_name>')

  53. -- CK 2005용
  54. -- DEFULT 2005용
  55. SELECT 'ALTER TBLE ' + object_name(parent_object_id)  + ' DROP CONSTRAINT ' + name
  56. FROM sys.default_constraints  
  57. WHERE object_name(parent_object_id) = object_id('<@table_name, @sysname,@table_name>')


  58. -- FK 2000용
  59. SELECT 'ALTER TABLE ' + object_name(fkeyid) + ' DROP CONSTRAINT ' +  object_name(constid) 
  60. FROM sys.sysforeignkeys
  61. WHERE fkeyid = object_id ('<@table_name, @sysname,@table_name>')

  62. -- INDEX 2000용
  63. select  'ALTER TABLE ' + object_name(id) + ' DROP INDEX '  + name 
  64. from sys.sysindexes where  object_name(id) in ('GOODSDAQ_BANNER_POSITION')
  65. order by id, name




    

        


이 글은 스프링노트에서 작성되었습니다.

'T-SQL' 카테고리의 다른 글

T-SQL::DB_Restore_move_to  (0) 2010.06.03
T-SQL::Convert hex value to String 32bit  (0) 2010.06.03
SQL Server 2005 and 2008 Ranking Functions  (0) 2010.04.05
DMV::Index  (0) 2010.04.05
2010. 4. 5. 00:06

SQL Server 2005 and 2008 Ranking Functions

'T-SQL' 카테고리의 다른 글

T-SQL::Convert hex value to String 32bit  (0) 2010.06.03
T_SQL::CONSTRAINT조사  (1) 2010.06.03
DMV::Index  (0) 2010.04.05
T-SQL::특정 objects 찾기  (0) 2010.04.04
2010. 4. 5. 00:01

DMV::Index



SQL SERVER 2005 이상

SQL 2005는 DMV를 통해서 실시간으로 인덱스의 사용빈도, 변경 횟수, lock 현황, missing 된 인덱스 정보를 제공한다.

이 자료를 바탕으로 튜닝과 관리 모니터링이 가능하다.

DMV의 정보는 마지막으로 SQL 인스턴스가 시작된 후로 누적된 값이다.

 사용하고 있는 INDEX 무엇인가?

 DDL 문을 통해 인덱스를 생성하게 되면 인덱스가 카탈로그는 업데이트 된다.

 그렇다고 이 인덱스가 "USE" 사용되는 것은 아니다.  인덱스가 select, insert, update가 될 때 sys.dm_db_index_usage_stats 에서 정보를 찾을 수 있다.

 마지막으로 SQL SERVER를 방금 재 시작 했다면 sys.dm_db_index_usage_stats 정보를 찾을 수 없을 수도 있다.

 

user_seeks : 사용자 쿼리별 검색(Seek) 수입니다.

user_scans : 사용자 쿼리별 검색(Scan) 수입니다.

user_lookups :  사용자 쿼리별 책갈피 조회 수입니다.

user_updates :  사용자 쿼리별 업데이트 수

 

사용하지 않는 테이블 & 인덱스

  1. -- unused tables & indexes.

  2. DECLARE @dbid INT

  3. SET @dbid = DB_ID('AdventureWorks')

  4.  

     

  5. SELECT OBJECT_NAME(IDX.object_id) as object_name,

  6.        IDX.name AS index_name,

  7.        CASE WHEN IDX.type = 1 THEN 'Clustered'

  8.           WHEN IDX.type = 2 THEN 'Non-Clustered'

  9.           ELSE 'Unknown' END Index_Type

  10. FROM sys.dm_db_index_usage_stats  AS DIS

  11.       RIGHT OUTER JOIN sys.indexes AS IDX  ON DIS.object_id = IDX.object_id AND DIS.index_id = IDX.index_id

  12.       JOIN sys.objects AS OBJ  ON IDX.object_id = OBJ.object_ID

  13. WHERE  OBJ.type IN ('U', 'V') AND DIS.object_id IS NULL

  14. ORDER BY OBJECT_NAME(IDX.object_id), IDX.name

     

 

드물게 사용하는 인덱스

 

  1. DECLARE @dbid INT

  2. SET @dbid = DB_ID('AdventureWorks')

  3.  

  4. --- rarely used indexes appear first

  5. SELECT OBJECT_NAME(DIS.object_id) as object_name,

  6.        IDX.name AS index_name, IDX.index_id,

  7.        CASE WHEN IDX.type = 1 THEN 'Clustered'

  8.           WHEN IDX.type = 2 THEN 'Non-Clustered'

  9.           ELSE 'Unknown' END Index_Type,

  10.         DIS.user_seeks, DIS.user_scans, DIS.user_lookups, DIS.user_updates

  11. FROM sys.dm_db_index_usage_stats AS DIS

  12.             JOIN sys.indexes AS IDX ON DIS.object_id = IDX.object_id AND DIS.index_id = IDX.index_id

  13. WHERE DIS.database_id = @dbid AND objectproperty(DIS.object_id,'IsUserTable') = 1

  14.             --AND DIS.user_updates > 0 AND DIS.user_seeks = 0

                 --AND DIS.user_scans = 0 AND DIS.user_lookups  = 0  --(업데이트는 일어나는 사용되지 않은것, 관리 부담만 있다.)

  15. ORDER BY (DIS.user_updates + DIS.user_seeks + DIS.user_scans + DIS.user_lookups ) asc

 

인덱스에 lock 이 걸려있는 지 확인

  1.  declare @dbid int
  2. select @dbid = db_id()
  3. Select dbid=database_id, objectname=object_name(s.object_id)
    , indexname=i.name, i.index_id       --, partition_number
    , row_lock_count, row_lock_wait_count
    , [block %]=cast (100.0 * row_lock_wait_count / (1 + row_lock_count) as numeric(15,2))
    , row_lock_wait_in_ms
    , [avg row lock waits in ms]=cast (1.0 * row_lock_wait_in_ms / (1 + row_lock_wait_count) as numeric(15,2))
    from sys.dm_db_index_operational_stats (@dbid, NULL, NULL, NULL) s,   sys.indexes i
    where objectproperty(s.object_id,'IsUserTable') = 1
    and i.object_id = s.object_id
    and i.index_id = s.index_id
    order by row_lock_wait_count desc

 

실시간 LOCK 확인 -- 다른 LOOK 쿼리 확인. 구분 이해하기

위에 부분은 실시간으로 처리되는 것이 아니라 누적된 결과를 보는 쿼리 이다. 실시간으로 락이 걸려있는 상태를 확이낳려면 프로시저를 생성하고 처리 결과를 보는것도 좋은 방법이다.

  1. create proc sp_block_info
    as
    set rowcount ON
    select t1.resource_type as [lock type]
                ,db_name(resource_database_id) as [database]
                ,t1.resource_associated_entity_id as [blk object]
                ,t1.request_mode as [lock req]                                          --- lock requested
                ,t1.request_session_id as [waiter sid]                                  --- spid of waiter
                ,t2.wait_duration_ms as [wait time]        
                ,(select text from sys.dm_exec_requests as r                           --- get sql for waiter
                            cross apply sys.dm_exec_sql_text(r.sql_handle)
                            where r.session_id = t1.request_session_id) as waiter_batch
                ,(select substring(qt.text,r.statement_start_offset/2,
                                        (case when r.statement_end_offset = -1
                                        then len(convert(nvarchar(max), qt.text)) * 2
                                        else r.statement_end_offset end - r.statement_start_offset)/2)
                            from sys.dm_exec_requests as r
                            cross apply sys.dm_exec_sql_text(r.sql_handle) as qt
                            where r.session_id = t1.request_session_id) as waiter_stmt    --- statement blocked
                 ,t2.blocking_session_id as [blocker sid]                                 -- spid of blocker
         ,(select text from sys.sysprocesses as p                                         --- get sql for blocker
                            cross apply sys.dm_exec_sql_text(p.sql_handle)
                            where p.spid = t2.blocking_session_id) as blocker_stmt
                from
                sys.dm_tran_locks as t1,
                sys.dm_os_waiting_tasks as t2
    where  t1.lock_owner_address = t2.resource_address
    set rowcount OFF
    go

 


 SEE ALSO : http://blogs.msdn.com/sqlcat/archive/2005/12/12/502735.aspx

'T-SQL' 카테고리의 다른 글

T_SQL::CONSTRAINT조사  (1) 2010.06.03
SQL Server 2005 and 2008 Ranking Functions  (0) 2010.04.05
T-SQL::특정 objects 찾기  (0) 2010.04.04
T-SQL::Attach  (1) 2009.12.01
2010. 4. 4. 23:39

T-SQL::특정 objects 찾기

Problem

In the course of any database development project, searching for database objects is something you will probably do.  It can be any kind of search which is done using some text as the search mechanism. Some of the examples of search that a developer / DBA may make within a database or database server are: searching for a database object, searching for occurance of particular text within database objects, searching within the schema of a database object, search within the results of query results or entire tables, etc..

In this tip, we look at different mechanisms that can be used to facilitate this type of searching.

Solution

Searching is generally required across database objects, across databases, and also across database servers. There are different mechanism that can be used for different kinds of search requirements.  For this tip I will be using SQL Server Management Studio (SSMS) 2008.

We will look at four different ways for our search that cover various search requirements.

  1. SSMS Object Search
  2. T-SQL Scripts
  3. SQL Search Add-in
  4. SSMS Tools Pack Add-in
1) SSMS Object Search:

As a part of the enhancements in SSMS 2008, object explorer details window has a nice object search toolbar which allows context sensitive searching of database objects. As show in the below screenshot, I attempted searching database object named "Address".  It fetched all the tables that it found with the same name. But there can be many database object having the text "Address" within it, or "Address" text can also appear in the definition of the database object. Also you can use '%' as a wild card character along with the text that you want to search in the same way as you use it with "like" for T-SQL.



2) T-SQL Scripts:

This one is the most flexible to search anything you would like to search within your database server. Using this mechanism, you have the flexibility to interrogate any schema or data level information that you would like, but the only down-side is that you need to create code and create a set of scripts to search across databases. You can create parameterized stored procedures to faciliate the search. But if a change is required, either you need to create your stored procedures with all the parameters based on how you would like to slice and dice your search or you will need to change the code.

In the below screen-shot, I attempted searching the text "Address" within "AdventureWorks" database. I found a stored-procedure containing "Address" text within it's name. Then I created a query to search text "Address" within all the stored-procedures in this database. There is no limit to the kind of scripts that can be created for searching using this technique as long as you know which catalog views to use.



3) SQL Search Add-in:

This is a free SSMS add-in from Red Gate Software and can be downloaded from here. Once installed, it becomes visible on the toolbar. This search requires no explanation and the benefit is that you just type the text and see the results. You can also limit the scope for a database or type of database objects as per your requirement. It also shows you if the text you are searching for appeared in the name of the database object and definition of the database object.

In the screenshot below, you can see that I attempted searching "Address" keyword within "AdventureWorks" database, and then tried locating the stored procedure that we looked at using the T-SQL Script. It shows this stored procedure twice in the search result, as "Address" is a part of the name of this stored procedure and also "Address" appears in the definition of the stored procedure. Not only does it list the object, but also highlights the places where the text appeared in the definition.

The only downside is that it won't can not copy the search results from the grid. I have requested this feature from Red Gate Software and I heard back that there is a good possibility that this feature will get added.



4) SSMS Tools Pack Add-in:

This is another free SSMS add-in and can be downloaded from here. After installation, it can be accessed from the object explorer by right-clicking as shown below.  Also at context specific areas, it is availalbe by right-clicking. If we extend our search to the next level, say we want to search the entire database including all tables and every column for a text that contains "Napa", and we need a report of the same. See the screen-shot below, where I did a right-click on database and did a search on the entire database data for any text that contains the word "Napa". This add-in has a lot of featuers, I leave it to the reader to browse the rest of these features.

'T-SQL' 카테고리의 다른 글

SQL Server 2005 and 2008 Ranking Functions  (0) 2010.04.05
DMV::Index  (0) 2010.04.05
T-SQL::Attach  (1) 2009.12.01
T-SQL::테이블 ROWCOUNT, 사이즈  (0) 2009.11.27
2009. 12. 1. 15:04

T-SQL::Attach

Attach 스크립트 만들기

 

 

--==========================================
--DB 복원
--==========================================
SET NOCOUNT ON
DECLARE @sql            nvarchar(max)
DECLARE @sql_move       nvarchar(max)
DECLARE @move           nvarchar(200)
DECLARE @dbid           int


SET @sql_move = ''
SET @sql = ''
DECLARE cur_restore CURSOR FOR
      SELECT dbid
            , 'CREATE DATABASE ' + name + ' ON' + char(13)
      FROM sys.sysdatabases WHERE dbid > 4 and NAME != 'LiteSpeedLocal' 
      ORDER BY name

OPEN cur_restore
FETCH NEXT FROM cur_restore
INTO @dbid, @sql_move

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @move = ''

        DECLARE cur_move CURSOR FOR
            
            select '(NAME = ''' + name + ''', FILENAME = ''' + filename + '''),' 
            from sys.sysaltfiles
            where dbid = @dbid

        OPEN cur_move
        FETCH NEXT FROM cur_move
        INTO @move


        WHILE @@FETCH_STATUS = 0
        BEGIN
            SET @sql_move = @sql_move + @move + char(13)

            FETCH NEXT FROM cur_move
            INTO @move
        END
        CLOSE cur_move
        DEALLOCATE cur_move


    SET @sql = @sql + @sql_move + 'FOR ATTACH' + char(13)
  --  select @sql
    print @sql
    set @sql = ''
    FETCH NEXT FROM cur_restore 
    INTO @dbid, @sql_move

END
CLOSE cur_restore
DEALLOCATE cur_restore

'T-SQL' 카테고리의 다른 글

DMV::Index  (0) 2010.04.05
T-SQL::특정 objects 찾기  (0) 2010.04.04
T-SQL::테이블 ROWCOUNT, 사이즈  (0) 2009.11.27
T-SQL::Index Script  (1) 2009.11.19
2009. 11. 27. 14:21

T-SQL::테이블 ROWCOUNT, 사이즈

테이블의 rowcount와 예약된 공간, 인덱스 공간 사이즈.

sp_spaceused 를 사용해도 되지만, 테이블 여러개를 한번에 조회시 사용하면  좋다.

 

--==================================
-- DB 테이블 목록, row수 ceusee
-- =================================
DECLARE @tablename sysname
SET @tablename = ''
SELECT sys.name, ind.row_count
    ,convert(int,(sum(convert(numeric(15,2),reserved) * m.low /1024))) as 'reserved(KB)'
    ,convert(int,(sum(convert(numeric(15,2),used) * m.low /1024))) as 'indexp(KB)'
FROM sys.sysobjects as sys 
    join sys.dm_db_partition_stats as ind on sys.id = ind.object_id
    join sysindexes as i on  i.id = ind.object_id
    ,master.dbo.spt_values  as m
WHERE sys.type = 'U' and ind.index_id < 2 
    and m.number = 1 and m.type = 'E'
    and i.indid in (0,1,255)
    and sys.name  = @tablename
)
GROUP BY sys.name, ind.row_count

'T-SQL' 카테고리의 다른 글

T-SQL::특정 objects 찾기  (0) 2010.04.04
T-SQL::Attach  (1) 2009.12.01
T-SQL::Index Script  (1) 2009.11.19
T-SQL::List all indexes in database  (0) 2009.11.19
2009. 11. 19. 17:15

T-SQL::Index Script


현재 존재하는 Index 스크립트 생성.

T-SQL::List all indexes in database  에 관련 함수, view 생성해야함.

 

-- INDEX Script
SELECT  
    CASE WHEN T.TABLE_NAME IS NULL THEN 
        'CREATE ' 
        + CASE IS_UNIQUE WHEN 1 THEN ' UNIQUE' ELSE '' END 
        + CASE IS_CLUSTERED WHEN 1 THEN ' CLUSTERED' ELSE '' END 
        + ' INDEX [' + INDEX_NAME + '] ON [' + v.TABLE_NAME + ']' 
        + ' (' + COLUMN_LIST + ') ON ' + FILE_GROUP 
    ELSE 
        'ALTER TABLE ['+T.TABLE_NAME+']' 
        +' ADD CONSTRAINT ['+INDEX_NAME+']' 
        +' PRIMARY KEY ' 
        + CASE IS_CLUSTERED WHEN 1 THEN ' CLUSTERED' ELSE '' END 
        + ' (' + COLUMN_LIST + ')' 
    END 
FROM 
    dbo.vAllIndexes v 
LEFT OUTER JOIN 
    INFORMATION_SCHEMA.TABLE_CONSTRAINTS T  
ON 
    T.CONSTRAINT_NAME = v.INDEX_NAME 
    AND T.TABLE_NAME = v.TABLE_NAME  
    AND T.CONSTRAINT_TYPE = 'PRIMARY KEY' 
ORDER BY 
    v.TABLE_NAME, 
    IS_CLUSTERED DESC

'T-SQL' 카테고리의 다른 글

T-SQL::Attach  (1) 2009.12.01
T-SQL::테이블 ROWCOUNT, 사이즈  (0) 2009.11.27
T-SQL::List all indexes in database  (0) 2009.11.19
T-SQL::Total Disk Size 얻기 (OLE 사용)  (1) 2009.08.13
2009. 11. 19. 15:50

T-SQL::List all indexes in database

데이터 베이스에 있는 모든 인덱스 정보를 보기 위함.

sys.indexes, sys.index_columns, sys.columns  정보를 보면 복합 인덱스 일경우 row가 한개 이상으로 나타나서 한눈에 보기가 힘들다.



select  t.name as table_name ,ind.name as index_name, 
        ind.index_id, ic.index_column_id, col.name as column_name 
from    sys.indexes ind
inner join    sys.index_columns ic on ind.object_id = ic.object_id and ind.index_id = ic.index_id
inner join    sys.columns col on  ic.object_id = col.object_id and ic.column_id = col.column_id 
inner join    sys.tables t on  ind.object_id = t.object_id
where   ind.is_primary_key = 0   
    and ind.is_unique = 0     
    and ind.is_unique_constraint = 0    
    and t.is_ms_shipped = 0
order by    t.name, ind.name, ind.index_id, ic.index_column_id
 

그래서 다음과 같이 처리한다.

1. 함수 생성 :: 컬럼의 인덱스가 내림차순인지 오름차순인지 확인
CREATE FUNCTION dbo.GetIndexColumnOrder 
( 
    @object_id INT, 
    @index_id TINYINT, 
    @column_id TINYINT 
) 
RETURNS NVARCHAR(5) 
AS 
BEGIN 
    DECLARE @r NVARCHAR(5) 
    SELECT @r = CASE INDEXKEY_PROPERTY 
    ( 
        @object_id, 
        @index_id, 
        @column_id, 
        'IsDescending' 
    ) 
        WHEN 1 THEN N' DESC' 
        ELSE N'' 
    END 
    RETURN @r 
END ;

2. 인덱스의 모든 컬럼 정보

CREATE FUNCTION dbo.GetIndexColumns 
( 
    @table_name SYSNAME, 
    @object_id INT, 
    @index_id TINYINT 
) 
RETURNS NVARCHAR(4000) 
AS 
BEGIN 
    DECLARE 
        @colnames NVARCHAR(4000),  
        @thisColID INT, 
        @thisColName SYSNAME 
         
    SET @colnames = '[' + INDEX_COL(@table_name, @index_id, 1) + ']'  
        + dbo.GetIndexColumnOrder(@object_id, @index_id, 1) 
 
    SET @thisColID = 2 
    SET @thisColName = '[' + INDEX_COL(@table_name, @index_id, @thisColID) + '] '
        + dbo.GetIndexColumnOrder(@object_id, @index_id, @thisColID)
 
    WHILE (@thisColName IS NOT NULL) 
    BEGIN 
        SET @thisColID = @thisColID + 1 
        SET @colnames = @colnames + ', ' + @thisColName 
 
        SET @thisColName = INDEX_COL(@table_name, @index_id, @thisColID) 
            + dbo.GetIndexColumnOrder(@object_id, @index_id, @thisColID) 
    END 
    RETURN @colNames 
END ;


 

3.인덱스 정보

CREATE VIEW dbo.V_ALLINDEXES 
AS
SELECT TABLE_NAME = OBJECT_NAME(i.id), 
      INDEX_NAME = i.name, 
      COLUMN_LIST = dbo.GetIndexColumns(OBJECT_NAME(i.id), i.id, i.indid), 
      IS_CLUSTERED = INDEXPROPERTY(i.id, i.name, 'IsClustered'),
      IS_UNIQUE = INDEXPROPERTY(i.id, i.name, 'IsUnique'), FILE_GROUP = g.GroupName 
FROM sysindexes i
INNER JOIN sysfilegroups g ON i.groupid = g.groupid
WHERE (i.indid BETWEEN 1 AND 254) -- leave out AUTO_STATISTICS: 
 AND (i.Status & 64)=0 -- leave out system tables: 
 AND OBJECTPROPERTY(i.id, 'IsMsShipped') = 0 ; 

'T-SQL' 카테고리의 다른 글

T-SQL::Attach  (1) 2009.12.01
T-SQL::테이블 ROWCOUNT, 사이즈  (0) 2009.11.27
T-SQL::Index Script  (1) 2009.11.19
T-SQL::Total Disk Size 얻기 (OLE 사용)  (1) 2009.08.13
2009. 8. 13. 18:41

T-SQL::Total Disk Size 얻기 (OLE 사용)

디스크의 남은 용량은 xp_fixeddrives 를 이용해서 구할 수 있지만 디스크 전체 사이즈를 쉽게 얻기는 쉽지 않다.

여러 방법이 있었는데 그중 OLE 사용하는 방법이다.

 

이 방법을 사용하기 위해서는 기능 영역에 OLE 자동화 사용이 활성화 되어 있어야 한다.

서비스 되고 있는 DB 장비는 이 기능을 ON 해 놓지 않기에 평범하게 사용할 수는 없다.

 

(클릭해서 크게 보세요)

 

CREATE PROCEDURE sp_diskspace
AS
/*
   Displays the free space,free space percentage
   plus total drive size for a server
*/
SET NOCOUNT ON

DECLARE @hr int
DECLARE @fso int
DECLARE @drive char(1)
DECLARE @odrive int
DECLARE @TotalSize varchar(20)
DECLARE @MB bigint ; SET @MB = 1048576

CREATE TABLE #drives (drive char(1) PRIMARY KEY,
                      FreeSpace int NULL,
                      TotalSize int NULL)

INSERT #drives(drive,FreeSpace)
EXEC master.dbo.xp_fixeddrives

EXEC @hr=sp_OACreate 'Scripting.FileSystemObject',@fso OUT
IF @hr <> 0 EXEC sp_OAGetErrorInfo @fso

DECLARE dcur CURSOR LOCAL FAST_FORWARD
FOR SELECT drive from #drives
ORDER by drive

OPEN dcur

FETCH NEXT FROM dcur INTO @drive

WHILE @@FETCH_STATUS=0
BEGIN

        EXEC @hr = sp_OAMethod @fso,'GetDrive', @odrive OUT, @drive
        IF @hr <> 0 EXEC sp_OAGetErrorInfo @fso
       
        EXEC @hr = sp_OAGetProperty @odrive,'TotalSize', @TotalSize OUT
        IF @hr <> 0 EXEC sp_OAGetErrorInfo @odrive
                       
        UPDATE #drives
        SET TotalSize=@TotalSize/@MB
        WHERE drive=@drive
       
        FETCH NEXT FROM dcur INTO @drive

END

CLOSE dcur
DEALLOCATE dcur

EXEC @hr=sp_OADestroy @fso
IF @hr <> 0 EXEC sp_OAGetErrorInfo @fso

SELECT drive,
       FreeSpace as 'Free(MB)',
       TotalSize as 'Total(MB)',
       CAST((FreeSpace/(TotalSize*1.0))*100.0 as int) as 'Free(%)'
FROM #drives
ORDER BY drive

DROP TABLE #drives

RETURN
go

'T-SQL' 카테고리의 다른 글

T-SQL::Attach  (1) 2009.12.01
T-SQL::테이블 ROWCOUNT, 사이즈  (0) 2009.11.27
T-SQL::Index Script  (1) 2009.11.19
T-SQL::List all indexes in database  (0) 2009.11.19