MSSQL CSV Formatında Saatlik Yedek Aldırma İşlemi

Bir projemizde kullanılan MSSQL Server Database sistemi için saatlik yedeklemelere ihtiyaç duyduk.

C#.Net ortamında çalışmaktadır. Otomatik olarak her saat yedek alabilmesi için ise outputtaki .exe dosyasını “Zamanlanmış Görevlere ( Task Scheduler )” zamanlanmış görev olarak çalıştırıyoruz. Veritabanındaki tabloları listeleyip tüm dataları dump ediyoruz. CSV formatında dosyaya yazıyoruz ve sıkıştırma işlemini gerçekleştiriyoruz. Böylece disk kaybı yaşamıyoruz.

Birden fazla Database mevcut ise önce onları çekip ayrı ayrı da çalıştırabilirsiniz. Geliştirilip farklı varsyonlarda eklenebilir. FTP olarak farklı bir alanada yükleme yapılabilir. Bu sistemde şuanda tüm dosyalar tutuluyor. Manuel olarak silmek yerine birkaç saat öncesine ait klasörleri silebilirsiniz. Diskten kazanmış olursunuz.

Program parçasını full olarak paylaşıyorum;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;
using System.Data;
using System.Text;
using System.IO.Compression;

namespace WindowsFormsApp7
{
	static class Program
	{
		/// 
<summary>
		/// The main entry point for the application.
		/// </summary>

		/// 
		private static string directoryPath = @"c:\temp";
		[STAThread]

		static void Main()
		{
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);

			SqlConnection sqlCon = new SqlConnection("Data Source=IP;Initial Catalog=DATABASE;User ID=USERNAME;Password=PASSWORD;MultipleActiveResultSets=True;");
			sqlCon.Open();
			string sql = "SELECT sc.name + '.' + ta.name TableName ,SUM(pa.rows) RowCnt FROM sys.tables ta INNER JOIN sys.partitions pa ON pa.OBJECT_ID = ta.OBJECT_ID INNER JOIN sys.schemas sc ON ta.schema_id = sc.schema_id WHERE ta.is_ms_shipped = 0 AND pa.index_id IN(1,0) GROUP BY sc.name,ta.name having SUM(pa.rows) > 0 and sc.name +'.'+ ta.name IN ( 'dbo.EFAT_ZARF' ) ORDER BY SUM(pa.rows) DESC";
			SqlCommand com = new SqlCommand(sql, sqlCon);
			SqlDataReader read = com.ExecuteReader();

			//string dirname = "DOSYAYOLU" + (DateTime.Now).ToString("yyyy-MM-dd");
			string dirname = "C:/SQL_BACKUP/" + (DateTime.Now).ToString("yyyy-MM-dd");
			CreateIfMissing(dirname);

			dirname += "/" + (DateTime.Now).ToString("HH");

			CreateIfMissing(dirname);
			string rar_dir = @"" + dirname;
			string rar_path = @"" + dirname + ".zip";
			List<string> filess = new List<string>();
			while (read.Read())
			{
				string fileName = dirname + "/" + read.GetValue(0) + ".csv";
				filess.Add(fileName);
				SqlCommand sqlCmd = new SqlCommand();
				sqlCmd.CommandText = "SELECT * FROM " + read.GetValue(0) + " with (NOLOCK)";
				sqlCmd.Connection = sqlCon;

				sqlCmd.Dispose();
				using (var CommandText = new SqlCommand("SELECT * FROM " + read.GetValue(0) + " with (NOLOCK)"))
				using (var reader = sqlCmd.ExecuteReader())
				//using (var outFile = File.CreateText(fileName))
				using (StreamWriter outFile = new StreamWriter(File.Open(fileName, FileMode.Create), Encoding.UTF8))
				{
					string[] columnNames = GetColumnNames(reader).ToArray();
					int numFields = columnNames.Length;
					outFile.WriteLine(string.Join(",", columnNames));
					if (reader.HasRows)
					{
						while (reader.Read())
						{
							string[] columnValues =
							Enumerable.Range(0, numFields)
							.Select(i => get_string( reader.GetValue(i) ))
							.Select(field => string.Concat("\"", field.Replace("\"", "\"\""), "\""))
							.ToArray();
							outFile.WriteLine(string.Join(",", columnValues));
						}
					}
				}

			}
			sqlCon.Close();
			directoryPath = rar_dir;
			DirectoryInfo directorySelected = new DirectoryInfo(directoryPath);
			Compress(directorySelected);
			foreach (var item in filess)
			{
				if (File.Exists(item))
				File.Delete(item);
			}
			
		}

		public static string get_string( object ss )
		{
			if (!(ss.ToString().Length > 2))
			return ss.ToString();
			if (ss.ToString().Substring(0, 2) == "0x")
			return System.Text.Encoding.UTF8.GetString((Byte[])ss);
			return ss.ToString();
		}

		public static string Base64Encode(string plainText)
		{
			var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
			return System.Convert.ToBase64String(plainTextBytes);
		}

		static void CreateIfMissing(string path)
		{
			bool folderExists = Directory.Exists(path);
			if (!folderExists)
			Directory.CreateDirectory(path);
		}

		static IEnumerable<string> GetColumnNames(IDataReader reader)
		{
			foreach (DataRow row in reader.GetSchemaTable().Rows)
			{
				yield return (string)row["ColumnName"];
			}
		}

		public static void Compress(DirectoryInfo directorySelected)
		{
			foreach (FileInfo fileToCompress in directorySelected.GetFiles())
			{
				using (FileStream originalFileStream = fileToCompress.OpenRead())
				{
					if ((File.GetAttributes(fileToCompress.FullName) & FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz")
					{
						using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz"))
						{
							using (GZipStream compressionStream = new GZipStream(compressedFileStream,CompressionMode.Compress))
							{
								originalFileStream.CopyTo(compressionStream);
							}
						}
						//FileInfo info = new FileInfo(directoryPath + "\\" + fileToCompress.Name + ".gz");
						//Console.WriteLine("Compressed {0} from {1} to {2} bytes.",fileToCompress.Name, fileToCompress.Length.ToString(), info.Length.ToString());
					}
				}
			}
		}
	}
}

 

 

 

Centos 7 PHP 7.2 ile MSSQL Server Bağlantısı

Projelerimizde genellikle PHP alt yapısı kullanmaktayız. Projenin bir bölümü MSSQL server ile bağlantılı çalıştığı için Linux web server’lar ile bağlantı yapamıyorduk. Bunun için Windows bir sunucu üzerinden IIS üzerine apache kurulumunu gerçekleştirip, MSSQL server’a bağlantı için PHP ye ait bir  “.dll ” kullanıp bağlantı sağlıyorduk. MSSQL tarafındaki işlemler için Windows sunucuyu web servis olarak kullanıyorduk.

Ne mi oluyordu ? Güzel oluyordu. Çalışıyor muydu ? Evet, çalışıyordu. İstediğimiz performans varmıydı ? Hayır, yoktu. Rahat mıydı ? Bize göre değildi.

4-5 sene içerisinde birkez defa PHP ile MSSQL’e bağlantılar denemiştik. Fakat çoğu kütüphane de BUG‘lar mevcuttu. Bu BUG‘lardan en sevdiğim ise Linux üzerinden MSSQL’e bağlandığınızda Sunucuda ne kadar RAM varsa hepsini kimseyi düşünmeden kendininmiş gibi kullanması. 🙂

Bizde zaman kaybetmemek adına Windows üzerinden web servis yazmaya başlayıp projelerimizi geliştirdik. Hemen hemen her yazılımcının, sistemcinin bir gece ansızın aklına düşen fikirleri, düşünceleri vardır. Benimkisi ise PHP ile MSSQL’e bağlanabilmek. Üstüne çok fazla düşmemiştim açıkcası.

Aradan günler geçti ve PHP’nin 7 sürümünde bazı güncellemeler olduğunu araştırırken bir abimiz PHP 7 ile MSSQL’e bağlandığını yazmış. Döküman ? Malesef. Sadece yazmış. 🙂

Şimdi geçelim Linux Centos 7 üzerinde PHP 7 ile MSSQL’e nasıl bağlantı kuracağımıza. ( Vesta Control Panel üzerinde de gayet güzel çalışmaktadır )

İşlemlerimizi PECL ile yapıyoruz. Komutlar;
# curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo
# yum update
# ACCEPT_EULA=Y yum install -y msodbcsql mssql-tools unixODBC-devel
# pecl install sqlsrv
# pecl install pdo_sqlsrv

PHP.INI dosyamıza aşağıdaki satırları ekleyip güncelliyoruz;
extension=sqlsrv
extension=pdo_sqlsrv

Web engine olarak ne kullanıyorsanız ( Nginx, Apache, PHP-FPM ) restart ediniz.

Bu kadar. Sonrasında ise kullanmış olduğunuz herhangi bir framework varsa direkt olarak database_driver değiştirirerek kullanabilirsiniz. Yok ise şuaradaki doküman işinize yarayabilir..

Karşılaşabileceğiniz hatalar;
# ACCEPT_EULA=Y yum install -y msodbcsql mssql-tools unixODBC-devel
bu satırda hata alırsanız Şuradaki doküman‘a göre Centos üzerinde aşağıdaki işlemleri sırasıyla gerçekleştiriyoruz ( Centos 7 – Redhat ).

sudo su
curl https://packages.microsoft.com/config/rhel/7/prod.repo &amp;amp;amp;amp;amp;amp;amp;gt; /etc/yum.repos.d/mssql-release.repo
exit
sudo yum remove unixODBC-utf16 unixODBC-utf16-devel
sudo ACCEPT_EULA=Y yum install msodbcsql17
sudo ACCEPT_EULA=Y yum install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' &amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;gt; ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' &amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;gt; ~/.bashrc
source ~/.bashrc
sudo yum install unixODBC-devel

PECL ile ilgili bir hata alırsanız ;
Şuradaki doküman’a göre aşağıdaki işlemleri yapınız.

yum install php-devel
yum provides pecl
yum install php70w-pear
pecl install stats

Kendi tecrübeme göre PHP’nin 7.2 versiyonu daha stabil ve hızlı çalışmakta. 7.2 versiyonu ile birlikte MSSQL’e bağlantılarımız gerçekleşiyor. Hatta Codeigniter framework’ü kullandığımız için Windows üzerindeki projeyi olduğu gibi Linux Centos üzerine aktardığımızda herhangi bir hata vs. almadan ( PHP tarafından ) kullanmaya devam ettik. Fakat sizin projelerinizde farklı veya özel kütüphaneler mevcut ise bunun garantisini veremem. Lütfen aktarım yapmadan önce TEST ortamında kontrol ediniz.

Ufak bir bilgilendirme;
Centos 7 versiyonundan farklı bir versiyonda denemedim. Farklı bir dağıtımda denemedim. Farklı kaynaklar ve kurulum dökümanları mevcut. Aynı zamanda kurulum sırasında UPDATE işlemi mevcut. Linux ( diğerlerinde de mevcut fakat bilen bilir 🙂 ) üzerinde her zaman yapmanız gereken birşey vardır; “Enter’a basmadan önce bir daha düşün” ilkesidir ve herşeyden önce mutalaka YEDEK alınız.

Kaynaklar;

  • https://github.com/Microsoft/msphpsql/issues/726
  • http://fafairuzcode.blogspot.com/2016/08/installing-pecl-on-centos-7.html
  • https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15
  • http://www.shukko.com/x3/2018/12/12/php-ile-mssql-sunucuya-baglanalim/