Sunday, 7 September 2014

SQL Server Import\ Export Image\Document Files

Documents storing inside database might be a requirement of SQL Server driven application. SQL Server uses nvarchar for unicode texts whereas varbinary data type for storing document files (like images, word documents, pdfs) in database.
Suppose you have a folder containing various document files (like images, word documents, pdfs, html) and it is required to perform certain actions to upload data from file system in to the database.

1.        List all files with their path in a folder and sub-folders to a Table
--------------------------------------------------------------------- 
CREATE PROCEDURE GetAllDirectoryFilesandFolders -- GetAllDirectoryFilesandFolders @RootDir='E:\Post\SqlCache'
(
@RootDir VARCHAR(1000)='E:\SQLCache'
)
AS
BEGIN

DECLARE  @RowIndex  INT
,        @SearchDir VARCHAR(1000)
  

IF EXISTS ( SELECT 1 FROM SQLCacheDocuments.SYS.TABLES WHERE name ='DocumentsRepository' ) 
DROP TABLE SQLCacheDocuments.dbo.DocumentsRepository


CREATE TABLE SQLCacheDocuments.dbo.DocumentsRepository
(
  FileID INT IDENTITY(1,1),
  DocumentFilePath VARCHAR(max),
  isfile INT,
  DocumentFileName VARCHAR(max),
  FileDepth INT
)

--- Get Root Direcotry Files\Folders
INSERT INTO DocumentsRepository(DocumentFileName, FileDepth,isFile)
EXEC MASTER.SYS.xp_dirtree @RootDir,1,1



--- If No file\Folder exits then exit 
IF NOT exists( SELECT * FROM DocumentsRepository )
RETURN


--- Update File\Folder Path
UPDATE DocumentsRepository
SET DocumentFilePath = @RootDir + '\' + DocumentFileName


--- Next root directory
SELECT @RowIndex=min(FileID) FROM DocumentsRepository


--- Get Sub Direcotry Files\Folders
WHILE 1=1
BEGIN

   SELECT @SearchDir = DocumentFilePath
   FROM DocumentsRepository
   WHERE FileID=@RowIndex

   INSERT INTO DocumentsRepository(DocumentFileName, FileDepth,isfile)
   EXEC MASTER.SYS.xp_dirtree @SearchDir,1,1

   UPDATE DocumentsRepository
   SET DocumentFilePath = @SearchDir + '\' + DocumentFileName
   WHERE DocumentFilePath is null

   SET @RowIndex = @RowIndex + 1

   -- Exit if current Rowindex is Max FileID
   IF ( @RowIndex > (SELECT max(FileID) FROM DocumentsRepository) or @RowIndex is null )
   BREAK

END


SELECT SUM(CASE ISFILE WHEN 0 THEN 1 ELSE 0 END )  TolalFolders
,      SUM(CASE ISFILE WHEN 1 THEN 1 ELSE 0 END )  TolalFiles
FROM  SQLCacheDocuments.dbo.DocumentsRepository


Delete
FROM  SQLCacheDocuments.dbo.DocumentsRepository
WHERE isfile=0


SELECT FileID, DocumentFilePath, DocumentFileName
FROM SQLCacheDocuments.dbo.DocumentsRepository
ORDER BY FileID

END
--------------------------------------------------------------------- 

2.       Divide files into two Tables based on operations
                                                   i.      Files (like Images, PDFs, Word documents ) which are inserted as binary
                                                 ii.       Files (text, HTML) whose content is inserted into the database
---------------------------------------------------------------------
SELECT * INTO SQLCacheDocuments.dbo.TextDocuments
FROM SQLCacheDocuments.dbo.DocumentsRepository
WHERE DocumentFileName like '%.html'
  OR  DocumentFileName like '%.TXT'
  
Alter table SQLCacheDocuments.dbo.TextDocuments ADD FileText NVARCHAR(max)

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

SELECT * INTO SQLCacheDocuments.dbo.HandDocuments
FROM SQLCacheDocuments.dbo.DocumentsRepository
WHERE DocumentFileName not like '%.html'
 AND  DocumentFileName not like '%.TXT'

ALTER TABLE SQLCacheDocuments.dbo.HandDocuments ADD FileBinary VARBINARY(max) 
---------------------------------------------------------------------

3. Import files (like Images, PDFs, Word documents ) as binary into the database table
--------------------------------------------------------------------- 
;WITH DocumentFiles
AS
(
SELECT FileID, DocumentFilePath
FROM SQLCacheDocuments.dbo.HandDocuments
WHERE FileBinary IS NULL
)
SELECT ' UPDATE SQLCacheDocuments.dbo.HandDocuments
                                 SET FileBinary= tempImg.BULKCOLUMN
                                  FROM OPENROWSET(BULK N''' + DocumentFilePath + ''', SINGLE_BLOB) as tempImg, SQLCacheDocuments.dbo.HandDocuments FileBinary
                                  WHERE CONVERT(int,FileBinary.FileID)='+ CONVERT(VARCHAR(200),FileID)+' GO '
FROM DocumentFiles
ORDER BY FileID
---------------------------------------------------------------------

4. Import content of files as text into the database table
--------------------------------------------------------------------- 
;WITH DocumentFiles
AS
(
SELECT FileID, DocumentFilePath
FROM SQLCacheDocuments.dbo.TextDocuments
WHERE FileText IS NULL
)
SELECT ' UPDATE SQLCacheDocuments.dbo.TextDocuments
                                 SET FileText= tempImg.BULKCOLUMN
                                  FROM OPENROWSET(BULK N''' + DocumentFilePath + ''', SINGLE_CLOB) as tempImg, SQLCacheDocuments.dbo.TextDocuments TextNote
                                  WHERE CONVERT(int,TextNote.FileID)='+ CONVERT(VARCHAR(200),FileID)+' GO '
FROM DocumentFiles
ORDER BY FileID
---------------------------------------------------------------------

5. Verify files binary by converting back to OS file
---------------------------------------------------------------------
;WITH DocumentFiles
AS
(
SELECT FileID, DocumentFileName
FROM SQLCacheDocuments.dbo.HandDocuments 
WHERE FILEID=1
)
SELECT ' EXEC master..xp_cmdshell ''BCP "SELECT FileBinary FROM SQLCacheDocuments.dbo. HandDocuments WHERE FileID ='
                        +Cast(FILEID as varchar(50))+'"  queryout "E:\Post\'+DocumentFileName
                        +'" -T -N -SsqlserverR2'''
FROM DocumentFiles
ORDER BY FileID
---------------------------------------------------------------------


6. Validate content of files by comparing OS file text and column value of database table.

7. Check files size and length of documents 
---------------------------------------------------------------------
SELECT (CAST(DATALENGTH(FileBinary)AS BIGINT) /1024.00) FileSize,* FROM SQLCacheDocuments.dbo.HandDocuments         
ORDER BY CAST(DATALENGTH(FileBinary) AS BIGINT) DESC       
        
SELECT Len(FileText),* FROM SQLCacheDocuments.dbo.TextDocuments
ORDER BY CAST(Len(FileText) AS BIGINT) DESC 
---------------------------------------------------------------------


Wednesday, 25 June 2014

Database Log files Shrinking DBCC SHRINKFILE

Shrinking database log file is necessary if log has grown out of control whether after a one-time data delete or where recovery model of the database is FULL and no log backups have been carried out. To reverse the effect of a one-time operation that caused unexpected log file growth are convincing reasons for shrinking a database\ database file.
Shrinking database is not a recommended process and should not be part of any regular maintenance operation but in any case you need to do so, you must REBUILD\ REORGANIZE indexes of database along with statistics update.

Script to shrink log files of all user created databases on server where some are with Simple'' and some are with 'Full' recovery model



Sunday, 15 June 2014

SQL Server Backup Types and Restore

Thin Black Lines ( Aasim Abdullah & Amna Aasif )



Every SQL Server database consists of a Master Data File (an OS file with the “.MDF” extension) to store user data. Log Files, or OS files with the “.LDF” extension, are also a necessary part of every database.  Log files record changes to data from requests by SQL queries.  Extra data files, or OS files with the “.NDF” extension can be added to a database.
Row data files are logically grouped into one or many File-Groups
Inside every row data file, user data is kept within boundary of 8K data pages which are further grouped as Extents.

It is hard to imagine not backing up the production databases periodically. This facilitates recovery from accidental data deletion or complete database corruption.  IN addition to recovery, database backups are also necessary when we need to move a database between different instances and need to archive unused data.

SQL Server allows four different types of backups, Full, Differential, Transaction Log, and File/File group backups.

Full Backup
A full database backup copies the entire database from all MDF, LDF, & NDF OS files into one OS file, typically given a “.BAK” file extension.

When a Full Database backup operation starts, the operation will first lock the database; effectively make the row data file/s read-only, without making the database inaccessible for ongoing & concurrent user transactions. It does so by placing a marker in the transaction log indicating what transactions pre-existed and will be copied to the BAK file.  After the transaction log marker has been set the lock is released and the backup will start copying database pages into the BAK OS file.

The backup operation copies only the pages that contain data while unused empty pages are skipped.

There is the possibility that users will modify data in the database while the backup is in progress. Once the data page copying process is complete, the backup operation will again lock the database; place the end marker in transaction log, release the lock and start copying appended changes from the transaction log between two markers.
This “log tail end” backup means every change which is from the initial marker to the second marker should be part of full backup.  In nearly all scenarios the BAK file is up-to-date to the moment the backup operation is complete. 

Full Database Backups are more disk I/O intensive which is why full backups take longer to complete. In between two full backups, data is secured by backing up only the changes since the most recent fill backup. That is possible through Differential or Transaction Backups.

Differential Backup
The first 9 pages of every data file are in the same sequence.  One of the 9 is the DCM (Differential Change Map).  DCM is a special header page which contain information about extents being modified after the last full backup operation.

Differential backups starts with scanning of DCM page/s. Each bit in a DCM page represents a single extent in the database file. Extents with bit value 0 mean none of its data page is changed since last full backup and are skipped during copy process.

Once extent copying process is done, just like in a full backup process, the differential backup process also backs up the transactional log from most recent full backup marker to bring the database to a stable state at the time the differential operation is complete.

Differential backup only contains data that has changed since the most recent Full backup.  So the operation takes up less space and I/O time compared to a full backup.

Therefore, for a large database we can add a full database backup with subsequent differential database backups to our backup plan.

Transaction Log Backup
The Transactional log contains serial records for every change made to a database data rows. Once query data changes are committed or roll backed, the data is considered part of inactive transactions in log file.

When a transaction log backup process starts, the process starts copying inactive transactions records created since the most recent backup operation of the transaction log e.g. the most recent Full, Differential, or Transaction log backup.

All transaction data considered inactive data in the transaction log are copied to the transaction log backup OS file.  The transaction log backup operation finishes by marking inactive data space as available and ready for reuse.

As Transaction log file is sequential so creating a transaction log backup is far more less time and I/O intensive as compared to full or differential backups.

Critical production databases are backed up with combination of full/differential and transactional backups.

File\File Group Backup
Larger database that consist of multiple files and file groups can be partially backed up, by creating File or File Group backups. It is recommended to also take transaction log or differential file\file-group backups at relatively close in time to File/File Group backups so recovery of a database will be founded on a consistent state backup files.