‏نمایش پست‌ها با برچسب SQL Server. نمایش همه پست‌ها
‏نمایش پست‌ها با برچسب SQL Server. نمایش همه پست‌ها

۱۳۹۰/۱۲/۲۱

نحوه تبديل نگارش SQL Server 2012 RTM مدت دار، به نگارش كامل


Microsoft® SQL Server® 2012 Evaluation از اين آدرس قابل دريافت است. همچنين اگر به سايت‌هاي وارز مراجعه كنيد، به ازاي هر نگارش SQL Server 2012، يك بسته دريافتي 4 گيگابايتي را به شما ارائه مي‌دهند. يعني اگر كسي بخواهد نسخه developer و نسخه enterprise را دريافت كند بيش از 8 گيگ را بايد دريافت نمايد!
اما واقعيت اين است كه نيازي به دريافت هيچكدام نيست. يك فايل ISO مربوط به SQL Server 2012 بيشتر وجود خارجي ندارد. تمام اين نگارش‌ها هم فقط براساس Product key است كه مشخص مي‌شوند. اگر سريال مرتبط با نگارش developer را وارد كنيد، اين نگارش نصب خواهد شد. اگر سريال نگارش enterprise را وارد كنيد، نگارش سازماني نصب خواهد شد؛ و تمام اين‌ها هم فقط با همان يك فايل ISO اصلي ارائه شده توسط مايكروسافت ميسر مي‌شوند.
اين فايل ISO اصلي را از اينجا مي‌توان دريافت كرد. بديهي است Product key توكار و پيش فرض آن كه در اختيار عموم است، مدت دار مي‌باشد. بنابراين حين نصب تنها نياز به سريال معتبر وجود دارد.

۱۳۹۰/۱۲/۱۹

Microsoft® SQL Server® 2012


نگارش نهايي Microsoft® SQL Server® 2012 چند روزي هست كه ارائه شده. فعلا نسخه آزمايشي RTM آن در اختيار عموم است.
در ادامه جمع آوري لينك‌هاي مرتبط به اين ارائه را مشاهده خواهيد نمود:


و يك جدول مقايسه‌اي بين امكانات نگارش‌هاي رايگان SQL Server 2012 در اينجا

۱۳۹۰/۰۷/۱۹

اگر نصب سرويس پك اس كيوال سرور Fail شد ...


همانطور كه مطلع هستيد سرويس پك سه SQL Server چند روزي است كه منتشر شده. اين به روز رساني بر روي يك سرور بدون مشكل نصب شد؛ در سرور ديگر به علت داشتن يك سري برنامه امنيتي مزاحم (كه مثلا دسترسي به رجيستري را مونيتور و سد مي‌كنند) با شكست مواجه و در آخر پيغام Fail نمايش داده شد. مجددا آنرا اجرا كردم، سريع تمام مراحل را تمام كرد باز هم Fail را نمايش داد.
خوب؛ گفتم احتمالا مشكلي نيست. سعي كردم به سرور وصل شوم ... پيغام «اين سرور دسترسي از راه دور را نمي‌پذيرد» و از اين حرف‌هاي متداول ظاهر شد. به لاگ موجود در Event log ويندوز كه مراجعه كردم پيغام خطاي زير نمايان بود:

Script level upgrade for database 'master' failed because upgrade step 'sqlagent100_msdb_upgrade.sql' encountered error 5597, state 1, severity 16. This is a serious error condition which might interfere with regular operation and the database will be taken offline. If the error happened during upgrade of the 'master' database, it will prevent the entire SQL Server instance from starting. Examine the previous errorlog entries for errors, take the appropriate corrective actions and re-start the database so that the script upgrade steps run to completion.

اوه! اوه! اوه! در اين لحظه‌ي عرفاني، ديتابيس master نابود شده! نمي‌شود وصل شد. سروري كه داشت تا مدتي قبل بدون هيچ مشكلي كار مي‌كرد، الان ديگر حتي نمي‌شود به آن وصل شد. به كنسول سرويس‌هاي ويندوز مراجعه كردم (services.msc)، سعي كردم سرويس اس كيوال را كه از كار افتاده دستي اجرا كنم، پيغام زير مجددا در event log ظاهر شد:

FILESTREAM feature could not be initialized. The Windows Administrator must enable FILESTREAM on the instance using Configuration Manager before enabling through sp_configure.

قابليت FILESTREAM را نمي‌تواند آغاز كند. پس از مدتي جستجو مشخص شد كه اين مورد را مي‌شود در رجيستري ويندوز غيرفعال كرد؛ به صورت زير:

1) Open up Registry Editor
2) Go To HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQLSERVER\FileStream
3) Edit the value "EnableLevel" and set it to 0
4) Restart SQL Server.

پس از انجام اينكار، سرويس اس كيوال استارت شد (از طريق كنسول سرويس‌هاي ويندوز). در ادامه، امكان اتصال به آن نبود (حتي با اكانت sa):

Login failed for user 'sa'. Reason: Server is in script upgrade mode. Only administrator can connect at this time. (Microsoft SQL Server, Error: 18401)


باز هم پس از مدتي جستجو معلوم گرديد كه «كمي بايد صبر كرد». آن پيغام اول كار مبتني بر تخريب ديتابيس master هم بي‌مورد است. پس از fail شدن نصب سرويس پك، هنوز برنامه نصاب آن در پشت صحنه مشغول به كار است. اين مورد به وضوح در task manager ويندوز مشخص است. سرور به مدت 15 دقيقه به حال خود رها شد. پس از آن بدون مشكل اتصال برقرار گرديد و همه چيز مجددا شروع به كار كرد.

بنابراين اگر در حين نصب سرويس پك SQL Server مشكلي پيش آمد، نگران نباشيد. بايد به نصاب آن زمان داد (برنامه mscorsw.exe در پشت صحنه مشغول به كار است). برنامه نصاب آن هم هيچ نوع خطاي مفهومي را گزارش نمي‌دهد. تمام مراحل، بجاي نمايش در برنامه تمام صفحه نصاب آن، در event log ويندوز ثبت مي‌شود. اين برنامه تمام صفحه فقط كارش نمايش يك progress bar است!


اگر ... هيچكدام از اين موارد جواب نداد، امكان بازسازي ديتابيس master نيز وجود دارد: [^ , ^]
ولي دست نگه داريد و سريع اقدام نكنيد. ابتدا به task manager مراجعه كنيد. آيا برنامه mscorsw.exe در حال اجرا است؟ اگر بله، يعني هنوز كار نصب تمام نشده. حداقل يك ربع بايد صبر كنيد.

۱۳۹۰/۰۵/۱۱

اتصال SQL Server به MySQL


اگر SQL Server و MySQL بر روي سيستم شما نصب است، روشي ساده براي انتقال اطلاعات بين اين دو وجود دارد كه نيازي به دخالت هيچ نوع برنامه‌ي جانبي نداشته و با امكانات موجود قابل مديريت است.

ايجاد يك Linked server

براي اينكه SQL Server را به MySQL متصل كنيم مي‌توان بين اين دو يك Linked server تعريف كرد و سپس دسترسي به بانك‌هاي اطلاعاتي MySQL همانند يك بانك اطلاعاتي محلي SQL Server خواهد شد كه شرح آن در ادامه ذكر مي‌شود.
ابتدا نياز است تا درايور ODBC مربوط به MySQL دريافت و نصب شود. آن‌را مي‌توانيد از اينجا دريافت كنيد : (+)
سپس management studio را گشوده و در قسمت Server objects ، بر روي گزينه‌ي Linked servers كليك راست نمائيد. از منوي ظاهر شده، گزينه‌ي New linked server را انتخاب كنيد:


در ادامه، بايد تنظيمات زير را در صفحه‌ي باز شده وارد كرد:


در قسمت Linked server و Product name ، نام دلخواهي را وارد كنيد.
Provider انتخابي بايد از نوع Microsoft OLE DB Provider for ODBC Drivers باشد.
مهم‌ترين تنظيم آن، قسمت Provider string است كه بايد به صورت زير وارد شود (در غير اينصورت كار نمي‌كند):
DRIVER={MySQL ODBC 5.1 Driver}; SERVER=localhost; DATABASE=testdb; USER=root; PASSWORD=mypass; OPTION=3;PORT=3306; CharSet=UTF8;
در اينجا نام ديتابيس پيش فرض، نام كاربري اتصال به MySQL و Password و غيره را مي‌توان تنظيم كرد.
پس از انجام اين تنظيمات بر روي دكمه‌ي Ok كليك كنيد تا Linked server ساخته شود:


اگر ليست بانك‌هاي اطلاعاتي را مشاهده نموديد، يعني اتصال به درستي برقرار شده است.

تنظيمات ثانويه:

تا اينجا اس كيوال سرور به MySQL متصل شده است، اما براي استفاده بهينه از امكانات موجود نياز است تا يك سري تغييرات ديگر را هم اعمال كرد.

تنظيم MSDASQL Provider :
در همان قسمت Linked provider ، ذيل قسمت Providers ، گزينه‌ي MSDASQL را انتخاب كرده و بر روي آن كليك راست نمائيد. سپس صفحه‌ي خواص آن‌را انتخاب كنيد تا بتوان تنظيمات زير را به آن اعمال كرد. اين پروايدر جهت اتصال به MySQL مورد استفاده قرار مي‌گيرد.



فعال سازي RPC :

براي اينكه بتوان از طريق SQL Server ركوردي را در يكي از جداول بانك‌هاي اطلاعاتي MySQL متصل شده ثبت نمود، مي‌توان از دستور زير استفاده كرد:
EXECUTE('insert into testdb.testtable(f1,f1) values(1,''data'')') at mysql

اينجا testdb نام بانك اطلاعاتي اتصالي MySQL است و testTable هم نام جدول مورد نظر. MySQL ايي كه در آخر عبارت ذكر شده همان نام linked server ايي است كه پيشتر تعريف كرديم.
به محض سعي در اجراي اين كوئري خطاي زير ظاهر مي‌شود:
Server 'mysql' is not configured for RPC.

براي رفع اين مشكل، مجددا به صفحه‌ي خواص همان liked server ايجاد شده مراجعه كنيد. در قسمت Server options دو گزينه مرتبط به RPC بايد فعال شوند:



و اكنون براي كوئري گرفتن از اطلاعات ثبت شده هم از عبارت زير مي‌توان استفاده كرد:
SELECT * FROM OPENQUERY(mysql, 'SELECT * FROM testdb.testtable')

در اين كوئري، MySQL نام Linked server ثبت شده است و testdb هم يكي از بانك‌هاي اطلاعاتي MySQL مورد نظر.


انتقال تمام اطلاعات يك جدول از بانك اطلاعاتي MySQL به SQL Server

پس از برقراري اتصال، اكنون import كامل يك جدول MySQL به SQL Server به سادگي اجراي كوئري زير مي‌باشد:
SELECT * INTO MyDb.dbo.testtable FROM openquery(MYSQL, 'SELECT * FROM testdb.testtable')

در اين كوئري، MySQL همان Linked server تعريف شده است. MyDB نام بانك اطلاعاتي موجود در SQL Server جاري است و testtable هم جدولي است كه قرار است اطلاعات testdb.testtable بانك اطلاعاتي MySQL به آن وارد شود.

با اطلاعات فارسي هم (در سمت SQL Server) مشكلي ندارد. همانطور كه مشخص است، در اطلاعات provider string ذكر شده‌، مقدار charset به utf8 تنظيم شده و همچنين اگر نوع collation فيلدهاي تعريف شده در MySQL نيز به utf8_persian_ci تنظيم شده باشد، با مشكل ثبت اطلاعات فارسي به صورت ???? مواجه نخواهيد شد.


نكته:
اگر بانك اطلاعاتي MySQL شما بر روي local host نصب نيست، جهت فعال سازي دسترسي ريموت به آن، مي‌توان به يكي از نكات زير مراجعه كرد و سپس اين اطلاعات جديد بايد در همان قسمت provider string مرتبط با تعريف linked server وارد شوند:


مطالب مشابه:

هيچكدام از اين روش‌ها قابل استفاده نبودند چون provider string صحيحي را نهايتا توليد نمي‌كنند. همچنين تمام اين روش‌ها مبتني است بر ايجاد DSN در كنترل پنل كه اصلا نيازي به‌ آن نيست و اضافي است.

۱۳۹۰/۰۴/۰۲

بررسي مقدار دهي اوليه متغيرها در T-SQL


يكي از موارد مشكل ساز حين استفاده از T-SQL ، مقدار دهي اوليه متغيرها به نال است و اگر اسكريپت تهيه شده كمي طولاني باشد، خطايابي مشكلات مرتبط با آن بسيار مشكل مي‌شود. براي مثال:
Declare
@x int,
@y int

Set @x = 1
If (@x + @y = 1)
BEGIN
print 'yes!'
End

Set @y = (select sum(id) from Account)
If @x + @y = 1
BEGIN
print 'yes!'
End

كد فوق بدون هيچگونه خطايي اجرا مي‌شود و هيچ وقت هم yes را چاپ نمي‌كند. مشكل هم همينجا است. خطايابي قسمت دوم اين اسكريپت كمي مشكل‌تر از حالت قبل است. چون در اينجا به نظر متغير y صريحا مقدار دهي شده است؛ اما در عمل ممكن است براي مثال به دليل عدم وجود ركوردي در جدول Account، باز هم null به آن نسبت داده شود.

بنابراين سؤال اين است كه چگونه اين نوع مشكلات را در يك پروژه با تعداد زيادي رويه ذخيره شده، تابع و غيره مي‌توان تشخيص داد؟
پاسخ:
در اين مورد قبلا مطلبي در اين سايت منتشر شده [+] (البته اگر از نگارش كامل VS 2010 استفاده مي‌كنيد نيازي به نصب چيزي نخواهيد داشت) و نكته‌ي آن بررسي SR0007 است.



۱۳۹۰/۰۳/۱۲

درك نمودار


سؤال: از نمودار زير چه چيزي را برداشت مي‌كنيد؟!



منحني كه بالا رفته يعني چي؟ يعني بده، خوبه؟!
منحني‌هاي پايين‌تر يعني چي؟ اين‌ها بهترند يا بالايي‌هاي آن‌ها؟
با بالا رفتن حجم فايل‌ها، كدام يك كارآيي بهتري دارد؟ بالايي‌ها يا پاييني‌ها؟


ماخذ اين نمودار:(+). البته قبل از مراجعه به ماخذ و مطالعه آن‌، سعي كنيد به سؤالات فوق پاسخ دهيد.

۱۳۹۰/۰۲/۰۸

ويندوز 7 و SQL Server 2008 موفق به كسب گواهينامه امنيتي شدند


نرم افزارهاي Windows 7, Windows Server 2008 R2 and SQL Server 2008 SP2 32 & 64 bit Enterprise Edition موفق به كسب گواهينامه امنيتي Common Criteria شدند. كسب اين مجوز امنيتي يكي از شروط اصلي و اجباري استفاده از يك نرم افزار در وزارت دفاع آمريكا است.
اين بررسي‌ها زير نظر وزارت دفاع و آژانس امنيت ملي آمريكا و همچنين آلمان برگزار شده و گزارش‌هاي مرتبط با ويندوز 7 و SQL Server 2008 را از اينجا مي‌توانيد دريافت كنيد: (+) و (+)

ماخذ: (+)


مطالب مشابه:
امنيت SQL Server 2008
مقايسه امنيتي نگارش‌هاي مختلف ويندوز

۱۳۸۹/۰۸/۲۷

مديريت كار تيمي با SQL Server


پس از انتشار جزوه‌ي SVN در حدود دو سال قبل، ايميل در اين مورد زياد داشتم. يكي از سؤالات هم اين بود كه: "چگونه از SVN جهت مديريت نگارش‌هاي مختلف يك بانك اطلاعاتي اس كيوال سرور در يك تيم استفاده كنيم؟ (منظور مديريت schema است)" و من هم پاسخ مناسبي براي اين مورد نداشتم چون كلاينت‌هاي SVN حداقل با Management studio يكپارچه نمي‌شود (بر خلاف ابزارهاي موجود براي VS.NET مانند VisualSVN ، AnkhSVN و غيره). صد البته مي‌شود از آن همانند اعمال نگارش به يك فايل Text معمولي مانند فايل‌هاي SQL استفاده كرد، اما خوب ...

و خبر خوب اينكه شركت معظم RedGate چند روز قبل يك كتاب رايگان را در اين مورد منتشر كرده است:



سرفصل‌هاي اين كتاب
Chapter 1: Writing Readable SQL
Chapter 2: Documenting your Database
Chapter 3: Change Management and Source Control
Chapter 4: Managing Deployments
Chapter 5: Testing Databases
Chapter 6: Reusing T-SQL Code
Chapter 7: Maintaining a Code Library
Chapter 8: Exploring your Database Schema
Chapter 9: Searching DDL and Build Scripts
Chapter 10: Automating CRUD
Chapter 11: SQL Refactoring

دريافت

۱۳۸۹/۰۷/۲۲

چك ليست نصب SQL Server


عموما هنگام نصب SQL Server ، پيش و پس از آن، بهتر است موارد زير جهت بالا بردن كيفيت و كارآيي سرور، رعايت شوند:

1- پيش فرض‌هاي نصب SQL Server در مورد محل قرارگيري فايل‌هاي ديتا و لاگ و غيره صحيح نيست. هر كدام بايد در يك درايو مجزا مسير دهي شوند براي مثال:
Data drive D:
Transaction Log drive E:
TempDB drive F:
Backup drive G:
اين مورد TempDB را كساني كه با SharePoint كار كرده باشند به خوبي علتش را درك خواهند كرد. پيش فرض نصب افراد تازه كار، نصب SQL Server و تمام مخلفات آن در همان درايو ويندوز است (يعني همان چندبار كليك بر روي دكمه‌ي Next براي نصب). SharePoint هم به نحو مطلوبي تمام كارهايش مبتني بر transactions ، استفاده از جداول موقتي و ذخيره فايل‌هاي حجيم در بانك اطلاعاتي است. يعني استفاده‌ي كامل از TempDB . نتيجه؟ پس از مراجعه به درايو ويندوز مشاهده خواهيد كرد كه فقط چند مگ فضاي خالي باقي مانده! حالا اينجا است كه بدو اين مقاله و اون مقاله رو بخون كه چطور TempDB را بايد از درايو C به جاي ديگري منتقل كرد. چيزي كه همان زمان نصب اوليه SQL Server بايد در مورد آن فكر مي‌شد و نه الان كه سيستم از كار افتاده.
همچنين وجود اين مسيرهاي مشخص و پيش فرض و آگاهي از سطوح دسترسي مورد نياز آن‌ها، از سر دردهاي بعدي جلوگيري خواهد كرد. براي مثال : انتقال فايل‌هاي ديتابيس اس كيوال سرور 2008

2- پس از رعايت مورد 1 ، نوبت به تنظيمات آنتي ويروس نصب شده روي سرور است. اين پوشه‌هاي ويژه را كه جهت فايل‌هاي ديتا و لاگ و غيره بر روي درايوهاي مختلف معرفي كرده‌ايد يا خواهيد نمود، بايد از تنظيمات آنتي ويروس شما Exclude شوند. همچنين در حالت كلي فايل‌هايي با پسوندهاي LDF/MDF/NDF بايد جزو فايل‌هاي صرفنظر شونده از ديد آنتي ويروس شما معرفي گردند.
اين مورد علاوه بر بالا بردن كارآيي SQL Server ، در حين Boot سيستم نيز تاثير گذار است. گاها ديده شده است كه آنتي ويروس‌ها اين فايل‌هاي حجيم را در حين راه اندازي اوليه سيستم، پيش از SQL Server ، جهت بررسي گشوده و به علت حجم بالاي آن‌ها اين قفل‌ها تا مدتي رها نخواهند شد. در نتيجه آغاز سرويس SQL Server را با مشكلات جدي مواجه خواهند كرد كه عموما عيب يابي آن كار ساده‌اي نيست.

3- پيش فرض ميزان حافظه‌ي مصرفي SQL Server صحيح نيست. اين مورد بايد دقيقا بلافاصله پس از پايان عمليات نصب اوليه اصلاح شود. براي مطالعه بيشتر: تنظيمات پيشنهادي حداكثر حافظه‌ي مصرفي اس كيوال سرور

4- آيا مطمئن هستيد كه از تمام امكانات نگارش جديد SQL Server ايي كه نصب كرده‌ايد در حال استفاده مي‌باشيد؟
براي مطالعه بيشتر: تنظيم درجه سازگاري يك ديتابيس اس كيوال سرور

5- بهتر است فشرده سازي خودكار بك آپ‌ها در SQL Server 2008 فعال شوند.
براي مطالعه بيشتر: +

6- از paging بيش از حد اطلاعات، از حافظه‌ي فيزيكي سرور به virtual memory و انتقال آن به سخت ديسك سيستم جلوگيري كنيد. براي اين منظور:
در قسمت Run ويندوز تاپيك كنيد : GPEDIT.MSC و پس از اجراي آن با مراجعه به Group policy editor ظاهر شده به مسير زير مراجعه كنيد:
windows settings -> security settings -> local policies -> user rights assignment -> lock pages in memory
در اينجا به يوزر اكانت سرويس SQL Server دسترسي lock pages in memory را بدهيد.
علاوه بر آن در همين قسمت (user rights assignment) گزينه‌ي "Perform Volume Maintenance tasks" را نيز يافته و دسترسي لازم را به يوزر اكانت سرويس SQL Server بدهيد.

7- به روز رساني اطلاعات آماري SQL Server را به حالت غيرهمزمان تنظيم كنيد.
اگر مطالب مرتبط با SQL Server اين سايت را مرور كرده باشيد حتما با يك سري DMV كه دقيقا به شما خواهند گفت بر اساس اطلاعات آماري جمع شده براي مثال بهتر است روي چه فيلدهايي Index درست كنيد، آشنا شده‌ايد. حالت پيش فرض به روز رساني اين اطلاعات آماري، synchronous است يا همزمان. به اين معنا كه تا اطلاعات آماري يك كوئري ذخيره نشود، حاصل كوئري به كاربر بازگشت داده نخواهد شد كه اين امر مي‌تواند بر روي كارآيي سيستم تاثير گذار باشد. اما امكان تنظيم آن به حالت غير همزمان نيز مطابق كوئري‌هاي زير وجود دارد (اين مورد از SQL Server 2005 به بعد اضافه شده است):

ALTER DATABASE dbName SET AUTO_UPDATE_STATISTICS ON
ALTER DATABASE dbName SET AUTO_UPDATE_STATISTICS_ASYNC ON

8- نصب آخرين سرويس پك موجود فراموش نشود. براي مثال اين سايت آمار تمام به روز رساني‌ها را نگهداري مي‌كند.

9- حتما رويه‌اي را براي تهيه بك آپ‌هاي خودكار پيش بيني كنيد. براي مثال : +

10- ميزان فضاي خالي باقيمانده درايوهاي سرور را مونيتور كنيد. اطلاعات بيشتر: +

11- با نصب سرور جديد و تنظيم collation آن به فارسي، به نكات "يافتن تداخلات Collations در SQL Server" دقت داشته باشيد.

۱۳۸۸/۱۱/۰۱

سرورهاي متصل شده‌ي SQL Server و مبحث تراكنش‌ها


يكي از قابليت‌هاي جالب SQL Server در يك شبكه محلي امكان link و اتصال آن‌ها به يكديگر است. به اين صورت امكان كوئري گرفتن (و يا اعمال متداول SQL ايي) از دو يا چند سرور مختلف با دستورات T-SQL ميسر مي‌شود؛ به نحوي كه حس يكپارچگي ديتابيس‌هاي اين سرورها را حين كوئري نوشتن خواهيم داشت.
براي مثال فرض كنيد دو سرور SQL1 و SQL2 را در شبكه داريم. مي‌خواهيم در سرور SQL1 اتصالي را به سرور SQL2 ايجاد كنيم.

USE master

EXEC sp_addlinkedserver
'SQL2',
N'SQL Server'

sp_addlinkedsrvlogin @useself='false ', @rmtsrvname = 'SQL2',
@rmtuser = 'sa',
@rmtpassword = 'pass#'

دستورات T-SQL فوق كار ثبت يك liked server جديد و اعمال مشخصات كاربري كه توسط آن قرار است به سرور SQL2 دسترسي داشت، انجام مي‌دهند.
اكنون جهت بررسي اين اتصال در سرور SQL1 كوئري زير را اجرا مي‌كنيم:

select * from sql2.faxManager.dbo.tblErja

كه نحوه‌ي فراخواني جدول مورد نظر بايد به صورت Server.DatabaseName.dbo.TableName در آن رعايت شود.
تا اينجا همه چيز خوب است. مشكل از زماني شروع مي‌شود كه بخواهيم تراكنش‌ها را نيز دخالت دهيم و اصولي كار كنيم. براي مثال:

begin distributed tran
select * from sql2.faxManager.dbo.tblErja
commit tran

خطايي كه در ويندوز سرور 2003 با آخرين به روز رساني‌ها ظاهر مي‌شود به صورت زير است:

The operation could not be performed because OLE DB provider for linked server was unable to begin a distributed transaction.
OLE DB provider for linked server returned message "The partner transaction manager has disabled its support for remote/network transactions.".


به صورت پيش فرض اين نوع تراكنش‌هاي توزيع شده غيرفعال هستند مگر اينكه فعال شوند و روش حل مشكل نيز به صورت زير مي‌باشد:
قبل از هر كاري به كنسول سرويس‌هاي ويندوز مراجعه كرده و از در حال اجرا بودن سرويس Distribute Transaction Coordinator اطمينان حاصل كنيد.
سپس به قسمت زير مراجعه نمائيد:
Control Panel > Administrative Tools > Component Services


نود مربوط به Component Service را گشوده و سپس بر روي My Computer كليك راست كرده و گزينه‌ي خواص را انتخاب كنيد.
در صفحه‌ي بازه شده به برگه‌ي MSTDC مراجعه كرده و بر روي دكمه‌ي Security Configuration كليك نمائيد.
اكنون تنظيمات آن‌را مطابق شكل زير تغيير دهيد.


اين تنظيم بايد بر روي هر دو سرور SQL1 و SQL2 انجام شود.

پس از اين تغييرات كه شامل راه اندازي مجدد سرويس Distribute Transaction Coordinator نيز خواهد شد، مشكل خطاي فوق برطرف شده و امكان استفاده از تراكنش‌ها در linked servers نيز ميسر مي‌شود.

مشكل ديگري كه به آن برخوردم خطاي زير است:

Unable to start a nested transaction for OLE DB provider for linked server . A nested transaction was required because the XACT_ABORT option was set to OFF.
OLE DB provider for linked server returned message "Cannot start more transactions on this session.".


براي حل اين مشكل يك سطر زير را بايد به ابتداي كوئري خود اضافه كرد كه جزو الزامات تراكنش‌هاي توزيع شده است و به اين صورت از rollback كامل تمامي دستورات موجود فراخواني شده T-SQL در صورت بروز كوچكترين خطايي اطمينان حاصل مي‌كند:
SET XACT_ABORT ON


براي مطالعه بيشتر:
MSDTC Troubleshooting

۱۳۸۸/۱۰/۲۷

تهيه گزارش از منسوخ شده‌هاي مورد استفاده در SQL Server 2008


مطلب "منسوخ شده‌ها در نگارش‌هاي جديد SQL server" را احتمالا به خاطر داريد. جهت تكميل آن، كوئري زير را هم مي‌توان ذكر كرد:

SELECT instance_name,
cntr_value
FROM sys.dm_os_performance_counters
WHERE OBJECT_NAME = 'SQLServer:Deprecated Features'
AND cntr_value > 0
ORDER BY
cntr_value DESC

توسط اين كوئري گزارشي از منسوخ شده‌هاي مورد استفاده‌ در ديتابيس‌هاي شما ارائه مي‌شود. براي مثال چندبار از text و ntext استفاده كرده‌ايد، آيا هنوز compatibility level ديتابيس‌هاي خود را تغيير نداده‌ايد و مثال‌هايي از اين دست.

براي مثال جهت يافتن سريع فيلدهاي منسوخ شده text و image ديتابيس جاري از كوئري زير مي‌توان كمك گرفت:
SELECT O.Name,
col.name AS ColName,
systypes.name
FROM syscolumns col
INNER JOIN sysobjects O
ON col.id = O.id
INNER JOIN systypes
ON col.xtype = systypes.xtype
WHERE O.Type = 'U'
AND OBJECTPROPERTY(o.ID, N'IsMSShipped') = 0
AND systypes.name IN ('text', 'ntext', 'image')
ORDER BY
O.Name,
Col.Name

۱۳۸۸/۱۰/۱۳

دريافت خطاي database is not accessible و نحوه‌ي رفع مشكل


ممكن است هنگام تلاش جهت اتصال به ديتابيس اس كيوال سرور 2005 به بعد از طريق management studio با پيغام خطاي زير مواجه شويد:
The database XYZ is not accessible. (ObjectExplorer)

و يا اگر بر روي همين ديتابيس كليك راست كرده و به خواص آن مراجعه كنيم، خطاي 952 زير صادر شود:

Database 'XYZ' is in transition. Try the statement later. (Microsoft SQL Server, Error: 952)

اصلا نگران نباشيد؛ هيچ مشكلي نيست!
ابتدا رويه‌ي ذخيره شده‌ي sp_who2 را اجرا كنيد. يك ليست از كانكشن‌هاي باز به ديتابيس‌هاي موجود را به شما خواهد داد.
در اين ليست به دنبال كانكشن‌هاي موجود به ديتابيسي كه اين خطا را مي‌دهد بگرديد. Pid اين كانكشن‌ها را يافته و سپس با دستور kill pid آن‌ها را از بين ببريد. مشكل حل خواهد شد.
عموما نبستن خود management studio سبب اين مشكل مي‌شود. بنابراين حتي يكبار باز و بسته كردن آن نيز بايد اين مشكل را برطرف كند (يا تمام management studio هاي متصل، كه البته راه ساده‌تر همان kill كردن pid آن‌ها است).

۱۳۸۸/۰۹/۲۸

مقايسه امنيت Oracle11g و SQL server 2008 از ديد آمار در سال 2009


جدول زير تعداد باگ‌هاي امنيتي Oracle11g و SQL server 2008 را تا ماه نوامبر 2009 نمايش مي‌دهد:


Product Advisories Vulnerabilities
SQL Server 2008 0 0
Oracle11g 7 239


و به صورت خلاصه مايكروسافت در 6 سال گذشته تنها 59 باگ امنيتي وصله شده مربوط به نگارش‌هاي مختلف SQL Server داشته است (از نگارش 2000 به بعد). در طي همين مدت اوراكل (نگارش‌هاي 8 تا 10) تعداد 233 وصله امنيتي را ارائه داده است.
در سال 2006 ، اس كيوال سرور 2000 با سرويس پك 4 ، به عنوان امن‌ترين بانك اطلاعاتي موجود در بازار شناخته شد (به همراه PostgreSQL). در همين زمان Oracle10g در قعر اين جدول قرار گرفت.

اعداد و آمار از سايت secunia.com استخراج شده است: + و +

۱۳۸۸/۰۹/۲۶

عدم كاهش حجم لاگ فايل SQL Server


در مورد روش‌هاي كاهش حجم لاگ فايل‌هاي SQL Server در اين مطلب بحث شد.
اما يكي از ديتابيس‌هاي قديمي shrink نمي‌شد و پيغام خطاي زير را صادر مي‌كرد:

Cannot shrink log file 2 because of minimum log space required.

يكي از علت‌هايي كه اگر مطابق روش ذكر شده در مقاله ياده شده رفتار شود، سبب كاهش حجم لاگ فايل يك ديتابيس نمي‌شود، وجود تراكنش‌هاي كامل نشده است. جهت مشاهده‌ي وضعيت تراكنش‌هاي يك ديتابيس مي‌توان دستور زير را صادر كرد:

DBCC OPENTRAN
كه نتيجه به صورت زير بود:

Replicated Transaction Information:
Oldest distributed LSN : (0:0:0)
Oldest non-distributed LSN : (5291:25:1)

وجود سطر مربوط به Oldest non-distributed LSN به اين معنا است كه هنوز يك replication نا تمام بر روي اين ديتابيس موجود است. البته چون اين ديتابيس از يك سرور ديگر به اينجا منتقل شده بود و هيچ نوع replication ايي هم در اين سرور بر روي آن تنظيم نشده بود؛ بنابراين ابتدا اين replication حذف شد:
exec sp_removedbreplication 'dbName', 'both';

سپس مجددا دستور زير جهت مشاهده‌ي وضعيت تراكنش‌هاي ناتمام صادر شد:
DBCC OPENTRAN

كه اين‌بار ديگر هيچ خروجي نداشت.
اكنون با استفاده از روش ذكر شده، لاگ فايل 70 گيگابايتي اين ديتابيس به سادگي به چند مگابايت shrink شد.

۱۳۸۸/۰۸/۲۸

يافتن تداخلات Collations در SQL Server


اگر ديتابيس خود را در طي چند سال از يك نگارش به نگارشي ديگر يا از يك سرور به سروري ديگر منتقل كرده باشيد، به احتمال زياد به مشكلات Collations هم برخورده‌ايد. يكي از فيلدها Arabic_CI_AS است (بجا مانده از دوران قبل از SQL Server 2008) در يك جدول و در جدولي ديگر فيلدي تازه‌اي با Collation از نوع Persian_100_CI_AS تعريف شده است. Collations نحوه ذخيره سازي و مقايسه رشته‌ها را كنترل مي‌كنند. زمانيكه يك جدول جديد را در SQL Server ايجاد مي‌كنيم، اگر Collation فيلدها به صورت صريح ذكر نگردند، بر مبناي همان Collation پيش فرض ديتابيس تعريف خواهند شد.
بنابراين اگر پس از استفاده از SQL Server 2008 و تنظيم Collation پيش فرض ديتابيس به Persian_100_CI_AS ، به اين موارد دقت نكنيم، دير يا زود دچار مشكل خواهيم شد.
عمليات مرتب سازي با وجود تداخلات Collations مشكل ساز نمي‌شود (خطايي دريافت نمي‌كنيد)، اما ممكن است الزاما صحيح عمل نكند. مشكل از آنجايي آغاز مي‌شود كه قصد داشته باشيم داده‌ها را مقايسه كنيم يا join ايي بين اين دو جدول با فيلدهاي ناهمگون از لحاظ Collation ايجاد نمائيم. در اين حالت حتما خطاهاي تداخل Collation را دريافت كرده و كوئري‌هاي ما اجرا نخواهند شد.
Cannot resolve collation conflict for equal to operation

يك راه حل اين است كه در حين join به صورت صريح collation هر دو فيلد ذكر شده را به صورت يكسان ذكر كنيم كه بيشتر يك مرهم موقتي است تا راه حل اصولي. براي مثال:
SELECT ID
FROM ItemsTable
INNER JOIN AccountsTable
WHERE ItemsTable.Collation1Col COLLATE DATABASE_DEFAULT
= AccountsTable.Collation2Col COLLATE DATABASE_DEFAULT
راه ديگر اين است كه مشخص كنيم كه Collation كدام فيلدها در ديتابيس با Collation پيش فرض ديتابيس تطابق ندارند. سپس بر اساس اين ليست شروع به تغيير Collations نمائيم.
اسكريپت زير تمام فيلدهاي ناهمگون از لحاظ Collation ديتابيس جاري را براي شما ليست خواهد كرد:
DECLARE @defaultCollation NVARCHAR(1000)
SET @defaultCollation = CAST(
DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS NVARCHAR(1000)
)

SELECT C.Table_Name,
Column_Name,
Collation_Name,
@defaultCollation DefaultCollation
FROM Information_Schema.Columns C
INNER JOIN Information_Schema.Tables T
ON C.Table_Name = T.Table_Name
WHERE T.Table_Type = 'Base Table'
AND RTRIM(LTRIM(Collation_Name)) <> RTRIM(LTRIM(@defaultCollation))
AND COLUMNPROPERTY(OBJECT_ID(C.Table_Name), Column_Name, 'IsComputed') = 0
ORDER BY
C.Table_Name,
C.Column_Name
براي مثال جهت تغيير Collation فيلد Serial از جدول tblArchive از نوع nvarchar با طول 200 به Persian_100_CI_AS مي‌توان از دستور T-SQL زير استفاده كرد:
ALTER TABLE [tblArchive] ALTER COLUMN [Serial] nvarchar(200) COLLATE Persian_100_CI_AS not null

۱۳۸۸/۰۸/۲۰

راهنماي مديريت ديتابيس‌هاي SharePoint


مايكروسافت اخيرا كتابچه‌اي را منتشر كرده است كه در آن نحوه‌ي نگهداري و بهبود كارآيي ديتابيس‌هاي اس كيوال سرور 2008 مخصوص شيرپوينت 2007 را توضيح داده است. حتي اگر سر و كار شما با شيرپوينت نيست اما با ديتابيس‌هاي حجيم و غول پيكر اس كيوال سرور 2008 سر و كار داريد، خواندن نكات اين مجموعه توصيه مي‌شود.

دريافت اين راهنما با فرمت pdf
دريافت اين راهنما با فرمت docx


۱۳۸۸/۰۸/۱۳

مرجعي در مورد نگارش‌هاي مختلف SQL Server


آيا مي‌دانيد كه تا اين تاريخ پس از ارائه سرويس پك يك اس كيوال سرور 2008، دقيقا 5 به روز رساني ديگر نيز در مورد آن منتشر شده‌اند؟
آيا مي‌دانيد پس از ارائه سرويس پك سه مربوط به اس كيوال سرور 2005 ، دقيقا 10 مورد به روز رساني ديگر آن نيز منتشر گرديده‌اند؟
آيا مي‌دانيد پس از سرويس پك 4 اس كيوال سرور 2000 دقيقا چند مورد به روز رساني مرتبط با آن منتشر شده‌اند؟ (72 مورد!)
آيا مي‌دانيد دقيقا از چه نگارشي از SQL Server با كدام به روز رساني‌ها استفاده مي‌كنيد؟

پاسخ دقيق به تمام اين سؤالات را به صورت طبقه بندي شده و بسيار منظم، در وبلاگ زير مي‌توانيد مشاهده نمائيد:



۱۳۸۸/۰۷/۳۰

به روز رساني فيلدهاي XML در SQL Server - قسمت دوم


قسمت اول را در اين آدرس مي‌توانيد مطالعه نمائيد.

در ادامه قسمت اول، اگر بخواهيم نود جديدي را به فيلد XML موجود اضافه كنيم، روش انجام آن به صورت زير است (يكي از روش‌ها البته):

DECLARE @tblTest AS TABLE (xmlField XML)

INSERT INTO @tblTest
(
xmlField
)
VALUES
(
'<Sample>
<Node1>Value1</Node1>
<Node2>Value2</Node2>
<Node3>OldValue</Node3>
</Sample>'
)

DECLARE @Name NVARCHAR(50)
SELECT @Name = 'Vahid'

UPDATE @tblTest
SET xmlField.modify(
'insert element Node4 {sql:variable("@Name")} as last into
(/Sample)[1]'
)

SELECT tt.xmlField
FROM @tblTest tt

كه حاصل آن (افزوده شدن يك المان جديد به نام Node4 بر اساس مقدار متغير Name در انتهاي ليست) به صورت زير مي‌باشد:

<Sample>
<Node1>Value1</Node1>
<Node2>Value2</Node2>
<Node3>OldValue</Node3>
<Node4>Vahid</Node4>
</Sample>

سؤال 1 :
اگر بخواهيم نام Node4 نيز متغير باشد به چه صورتي بايد مساله را حل كرد؟
در اين حالت بايد از كوئري‌هاي دايناميك استفاده كرد. بايد يك رشته را ايجاد (كل عبارت update بايد يك رشته شود) و سپس از دستور exec كمك گرفت و البته بايد دقت داشت در اين حالت كار encoding كاركترهاي غيرمجاز در XML را بايد خودمان انجام دهيم.

سؤال 2:
اگر بخواهيم نام نودها و مقادير آن‌ها را به صورت يك جدول معمولي بازگشت دهيم به چه صورتي بايد عمل كرد؟

DECLARE @XML AS XML

SELECT @XML = tt.xmlField
FROM @tblTest tt

SELECT t.c.value('local-name(..)', 'varchar(max)') AS ParentNodeName,
t.c.value('local-name(.)', 'varchar(max)') AS NodeName,
t.c.value('text()[1]', 'varchar(max)') AS NodeText

FROM @XML.nodes('/*/*') AS t(c)

كه پس از اجراي آن خواهيم داشت:

ParentNodeName - NodeName - NodeText
Sample Node1 Value1
Sample Node2 Value2
Sample Node3 OldValue
Sample Node4 Vahid

۱۳۸۸/۰۷/۱۲

با رويه‌هاي ذخيره شده خود، وب سرويس ايجاد كنيد


قابليت جالبي از SQL Server 2005 به بعد به اين محصول اضافه شده است كه امكان ايجاد يك وب سرويس بومي را بر اساس رويه‌هاي ذخيره شده و يا توابع تعريف شده در ديتابيس‌هاي موجود، فراهم مي‌سازد. اين قابليت نيازي به IIS يا هر هاست ديگري براي اجرا ندارد و توسط خود اس كيوال سرور راه اندازي و مديريت مي‌شود.
توضيحات مفصل آن‌‌را در MSDN مي‌توانيد ملاحظه كنيد و در اينجا يك مثال عملي از آن را با هم مرور خواهيم كرد:

الف) ايجاد يك جدول آزمايشي به همراه تعدادي ركورد دلخواه در آن

CREATE TABLE [tblWSTest](
[id] [int] IDENTITY(1,1) NOT NULL,
[f1] [nvarchar](50) NULL,
[f2] [nvarchar](500) NULL,
CONSTRAINT [PK_tblWSTest] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

SET IDENTITY_INSERT [tblWSTest] ON
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (1, N'a1', N'a2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (2, N'b1', N'b2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (3, N'c1', N'c2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (4, N'd1', N'd2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (5, N'e1', N'e2')
SET IDENTITY_INSERT [dbo].[tblWSTest] OFF
ب) ايجاد يك رويه ذخيره شده در ديتابيس جاري

CREATE PROCEDURE GetAllData
AS
SELECT f1,
f2
FROM tblWSTest
ج) ايجاد يك HTTP Endpoint

CREATE ENDPOINT GetDataService
STATE = STARTED
AS HTTP(
PATH = '/GetData',
AUTHENTICATION = (INTEGRATED),
PORTS = (CLEAR),
CLEAR_PORT = 8080,
SITE = '*'
)
FOR SOAP(
WEBMETHOD 'GetAllData'
(NAME = 'testdb2009.dbo.GetAllData'),
WSDL = DEFAULT,
DATABASE = 'testdb2009',
NAMESPACE = DEFAULT
)

توضيحات:
Ports در حالت clear و يا ssl مي‌تواند باشد. همچنين براي اينكه با IIS موجود بر روي سيستم هم تداخل نكند CLEAR_PORT به 8080 تنظيم شده است. ساير پارامترهاي آن بسيار واضح هستند. براي مثال تعيين ديتابيسي كه اين رويه ذخيره شده در آن قرار دارد و همچنين مسير كامل دسترسي به آن دقيقا مشخص مي‌گردند.


اين وب سرويس هم اكنون آغاز به كار كرده است. براي مشاهده wsdl آن، آدرس زير را در مرورگر وب خود وارد نمائيد (PATH و CLEAR_PORT معرفي شده در endPoint اينجا بكار مي‌رود):

http://localhost:8080/GetData?wsdl

د) استفاده از اين وب سرويس در يك برنامه ويندوزي
يك برنامه ساده winForms را شروع كنيد. سپس يك DataGridView را بر روي فرم قرار دهيد (بديهي است اين مورد مي‌تواند يك برنامه ASP.Net هم باشد و موارد مشابه ديگر). سپس از منوي پروژه، يك service reference را در VS2008 بر اساس آدرس wdsl فوق اضافه كنيد (شكل زير):


براي اينكه اين مثال در VS2008 درست كار كند بايد فايل app.config ايجاد شده را كمي ويرايش كرد. قسمت security آن را يافته و تغييرات زير را با توجه به AUTHENTICATION مورد نياز تغيير دهيد:

<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
سپس كد برنامه ما به صورت زير خواهد بود:

using System;
using System.Data;
using System.Windows.Forms;

namespace WebServiceTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
ServiceReference1.GetDataServiceSoapClient data =
new ServiceReference1.GetDataServiceSoapClient();
dataGridView1.DataSource = (data.GetAllData()[0] as DataSet).Tables[0];
}
}
}




۱۳۸۸/۰۷/۰۶

آشنايي با قابليت FileStream اس كيوال سرور 2008 - قسمت سوم


در انتهاي قسمت قبل، نحوه‌ي ايجاد يك جدول جديد با فيلدي از نوع فايل استريم بررسي شد، حال اگر جدولي از پيش وجود داشت، نحوه‌ي افزودن فيلد ويژه مورد نظر به آن، به صورت زير است:

alter table tbl_files set(filestream_on ='default')

go
alter table tbl_files
add

[systemfile] varbinary(max) filestream null ,
FileId uniqueidentifier not null rowguidcol unique default (newid())
go

در ادامه جدول tblFiles قسمت قبل را در نظر بگيريد:

CREATE TABLE [tblFiles](
[FileId] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[Title] [nvarchar](255) NOT NULL,
[SystemFile] [varbinary](max) FILESTREAM NULL,
UNIQUE NONCLUSTERED
(
[FileId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] FILESTREAM_ON [fsg1]

ALTER TABLE [dbo].[tblFiles] ADD DEFAULT (newid()) FOR [FileId]
GO

نحوه‌ي افزودن ركوردي جديد به جدول tblFiles :

INSERT INTO [tblFiles]
(
[Title],
[SystemFile]
)
VALUES
(
'file-1',
CAST('data data data' AS VARBINARY(MAX))
)
در اينجا سعي كرده‌ايم يك رشته ساده را در فيلدي از نوع فايل استريم ذخيره كنيم كه روش كار به صورت فوق است. از آنجائيكه مقدار پيش فرض FileId را هنگام تعريف جدول به NEWID تنظيم كرده‌ايم، نيازي به ذكر آن نيست و به صورت خودكار محاسبه و ذخيره خواهد شد.
اگر كنجكاو باشيد كه اين فايل اكنون كجا ذخيره شده و نحوه‌ي مديريت آن توسط اس كيوال سرور به چه صورتي است، فقط كافي است به مسيري كه هنگام افزودن گروه فايل‌ها و فايل مربوطه در تنظيمات خواص ديتابيس در قسمت قبل مشخص كرديم، مراجعه كرد (شكل زير).



بديهي است افزودن يك رشته به اين صورت كاربرد عملي ندارد و صرفا جهت يك مثال ارائه شد. در ادامه، نحوه‌ي ثبت محتويات يك فايل را در فيلدي از نوع فايل استريم و سپس خواندن اطلاعات آن‌را از طريق برنامه نويسي بررسي خواهيم كرد:

using System;
using System.IO;
using System.Data.SqlClient;
using System.Data;

namespace FileStreamTest
{
class CFS
{
/// <summary>
/// افزودن ركورد به جدول حاوي ستوني از نوع فايل استريم
/// </summary>
/// <param name="filePath">مسير فايل</param>
/// <param name="title">عنواني دلخواه</param>
public static void AddNewRecord(string filePath, string title)
{
//آيا فايل وجود دارد؟
if (!File.Exists(filePath))
throw new FileNotFoundException(
"لطفا مسير فايل معتبري را مشخص نمائيد", filePath);

//خواندن اطلاعات فايل در آرايه‌اي از بايت‌ها
byte[] buffer = File.ReadAllBytes(filePath);

using (SqlConnection objSqlCon = new SqlConnection())
{
//todo: كانكشن استرينگ بايد از يك فايل كانفيگ خوانده شود
objSqlCon.ConnectionString =
"Data Source=(local);Initial Catalog=testdb2009;Integrated Security = true";
objSqlCon.Open();

//شروع يك تراكنش
using (SqlTransaction objSqlTran = objSqlCon.BeginTransaction())
{
//ساخت عبارت افزودن پارامتري
using (SqlCommand objSqlCmd = new SqlCommand(
"INSERT INTO [tblFiles]([Title],[SystemFile]) VALUES(@title , @file)",
objSqlCon, objSqlTran))
{
objSqlCmd.CommandType = CommandType.Text;

//تعريف وضعيت پارامترها و مقدار دهي آن‌ها
objSqlCmd.Parameters.AddWithValue("@title", title);
objSqlCmd.Parameters.AddWithValue("@file", buffer);

//اجراي فرامين
objSqlCmd.ExecuteNonQuery();
}

//پايان تراكنش
objSqlTran.Commit();
}
}
}

/// <summary>
/// دريافت اطلاعات فايل ذخيره شده به صورت آرايه‌اي از بايت‌ها
/// </summary>
/// <param name="fileId">كليد مورد استفاده</param>
/// <returns></returns>
public static byte[] GetDataFromDb(string fileId)
{
byte[] data = null;

using (SqlConnection objConn = new SqlConnection())
{
//كوئري اس كيوال پارامتري جهت دريافت محتويات فايل
string cmdText = "SELECT SystemFile FROM tblFiles WHERE FileId=@id";
using (SqlCommand objCmd = new SqlCommand(cmdText, objConn))
{
//todo: كانكشن استرينگ بايد از يك فايل كانفيگ خوانده شود
objConn.ConnectionString =
"Data Source=(local);Initial Catalog=testdb2009;Integrated Security = true";
objConn.Open();

//تنظيم كردن وضعيت و مقدار پارامتر تعريف شده در كوئري
objCmd.Parameters.AddWithValue("@id", fileId);

//اجراي فرامين و دريافت فايل
using (SqlDataReader objread = objCmd.ExecuteReader())
{
if (objread != null)
if (objread.Read())
{
if (objread["SystemFile"] != DBNull.Value)
data = (byte[])objread["SystemFile"];
}
}
}
}

return data;
}
}
}

مثالي در مورد روش استفاده از كلاس فوق :

using System.IO;

namespace FileStreamTest
{
class Program
{
static void Main(string[] args)
{
CFS.AddNewRecord(@"C:\filest05.PNG", "test1");

//آي دي ركورد ذخيره شده در ديتابيس براي مثال
byte[] data = CFS.GetDataFromDb("BB848D45-382C-4D95-BF4E-52C3509407D4");
if (data != null)
{
File.WriteAllBytes(@"C:\tst.PNG", data);
}
}
}
}
روش فوق با روش متداول افزودن يك فايل به ديتابيس اس كيوال سرور هيچ تفاوتي ندارد و اين‌جا هم بدون مشكل كار مي‌كند. اطلاعات نهايي به صورت فايل‌هايي بر روي سيستم كه توسط اس كيوال سرور مديريت خواهند شد و با جدول شما يكپارچه‌اند، ذخيره مي‌شوند.

در روش ديگري كه در اكثر مقالات مرتبط مورد استفاده است، از شيء SqlFileStream كمك گرفته شده و نحوه‌ي انجام آن نيز به صورت زير مي‌باشد.
در ابتدا دو رويه ذخيره شده زير را ايجاد مي‌كنيم:

CREATE PROCEDURE [AddFile](@Title NVARCHAR(255), @filepath VARCHAR(MAX) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;

DECLARE @ID UNIQUEIDENTIFIER
SET @ID = NEWID()

INSERT INTO [tblFiles]
(
[FileId],
[title],
[SystemFile]
)
VALUES
(
@ID,
@Title,
CAST('' AS VARBINARY(MAX))
)

SELECT @filepath = SystemFile.PathName()
FROM tblFiles
WHERE FileId = @ID
END
GO

CREATE PROCEDURE [GetFilePath](@Id VARCHAR(50))
AS
BEGIN
SET NOCOUNT ON;

SELECT SystemFile.PathName()
FROM tblFiles
WHERE FileId = @ID
END
در رويه ذخيره شده AddFile ، ابتدا ركوردي بر اساس عنوان دلخواه ورودي با يك فايل خالي ايجاد مي‌شود. سپس مسير سيستمي اين فايل را در آرگومان خروجي filepath قرار مي‌دهيم. SystemFile.PathName از اس كيوال سرور 2008 جهت فيلدهاي فايل استريم به اس كيوال سرور اضافه شده است. از اين مسير در برنامه خود جهت نوشتن بايت‌هاي فايل مورد نظر در آن توسط شيء SqlFileStream استفاده خواهيم كرد.
رويه ذخيره شده GetFilePath نيز تنها مسير سيستمي فايل استريم ذخيره شده را بر مي‌گرداند.
به اين ترتيب كدهاي برنامه به صورت زير تغيير خواهند كرد:

using System.Data.SqlClient;
using System.Data;
using System.Data.SqlTypes;
using System.IO;

namespace FileStreamTest
{
class CFSqlFileStream
{
/// <summary>
/// افزودن ركورد به جدول حاوي ستوني از نوع فايل استريم
/// </summary>
/// <param name="filePath">مسير فايل</param>
/// <param name="title">عنواني دلخواه</param>
public static void AddNewRecord(string filePath, string title)
{
//آيا فايل وجود دارد؟
if (!File.Exists(filePath))
throw new FileNotFoundException(
"لطفا مسير فايل معتبري را مشخص نمائيد", filePath);

//خواندن اطلاعات فايل در آرايه‌اي از بايت‌ها
byte[] buffer = File.ReadAllBytes(filePath);

using (SqlConnection objSqlCon = new SqlConnection())
{
//todo: كانكشن استرينگ بايد از يك فايل كانفيگ خوانده شود
objSqlCon.ConnectionString =
"Data Source=(local);Initial Catalog=testdb2009;Integrated Security = true";
objSqlCon.Open();

//شروع يك تراكنش
using (SqlTransaction objSqlTran = objSqlCon.BeginTransaction())
{
//استفاده از رويه ذخيره شده افزودن فايل
using (SqlCommand objSqlCmd = new SqlCommand(
"AddFile", objSqlCon, objSqlTran))
{
objSqlCmd.CommandType = CommandType.StoredProcedure;

//مشخص ساختن وضعيت و مقدار پارامتر عنوان
SqlParameter objSqlParam1 = new SqlParameter("@Title", SqlDbType.NVarChar, 255);
objSqlParam1.Value = title;

//مشخص ساختن پارامتر خروجي رويه ذخيره شده
SqlParameter objSqlParamOutput = new SqlParameter("@filepath", SqlDbType.VarChar, -1);
objSqlParamOutput.Direction = ParameterDirection.Output;

//افزودن پارامترها به شيء كامند
objSqlCmd.Parameters.Add(objSqlParam1);
objSqlCmd.Parameters.Add(objSqlParamOutput);

//اجراي رويه ذخيره شده
objSqlCmd.ExecuteNonQuery();

//و سپس دريافت خروجي آن
string Path = objSqlCmd.Parameters["@filepath"].Value.ToString();

//زمينه تراكنش فايل استريم موجود را دريافت كرده و از آن براي نوشتن محتويات فايل استفاده خواهيم كرد
//اين مورد نيز يكي از تازه‌هاي اس كيوال سرور 2008 است
using (SqlCommand objCmd = new SqlCommand(
"SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()", objSqlCon, objSqlTran))
{
byte[] objContext = (byte[])objCmd.ExecuteScalar();
using (SqlFileStream objSqlFileStream =
new SqlFileStream(Path, objContext, FileAccess.Write))
{
objSqlFileStream.Write(buffer, 0, buffer.Length);
}
}
}

objSqlTran.Commit();
}
}
}

/// <summary>
/// دريافت اطلاعات فايل ذخيره شده به صورت آرايه‌اي از بايت‌ها
/// </summary>
/// <param name="fileId">كليد مورد استفاده</param>
/// <returns></returns>
public static byte[] GetDataFromDb(string fileId)
{
byte[] buffer = null;

using (SqlConnection objSqlCon = new SqlConnection())
{
//todo: كانكشن استرينگ بايد از يك فايل كانفيگ خوانده شود
objSqlCon.ConnectionString =
"Data Source=(local);Initial Catalog=testdb2009;Integrated Security = true";
objSqlCon.Open();

//شروع يك تراكنش
using (SqlTransaction objSqlTran = objSqlCon.BeginTransaction())
{
//استفاده از رويه ذخيره شده دريافت مسير فايل
using (SqlCommand objSqlCmd =
new SqlCommand("GetFilePath", objSqlCon, objSqlTran))
{
objSqlCmd.CommandType = CommandType.StoredProcedure;

//مشخص ساختن پارامتر ورودي رويه ذخيره شده و مقدار دهي آن
SqlParameter objSqlParam1 = new SqlParameter("@ID", SqlDbType.VarChar, 50);
objSqlParam1.Value = fileId;
objSqlCmd.Parameters.Add(objSqlParam1);

//اجراي رويه ذخيره شده و دريافت مسير سيستمي فايل استريم
string path = string.Empty;
using (SqlDataReader sdr = objSqlCmd.ExecuteReader())
{
sdr.Read();
path = sdr[0].ToString();
}

//زمينه تراكنش فايل استريم موجود را دريافت كرده و از آن براي خواندن محتويات فايل استفاده خواهيم كرد
//اين مورد نيز يكي از تازه‌هاي اس كيوال سرور 2008 است
using (SqlCommand objCmd = new SqlCommand(
"SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()", objSqlCon, objSqlTran))
{
byte[] objContext = (byte[])objCmd.ExecuteScalar();

using (SqlFileStream objSqlFileStream =
new SqlFileStream(path, objContext, FileAccess.Read))
{
buffer = new byte[(int)objSqlFileStream.Length];
objSqlFileStream.Read(buffer, 0, buffer.Length);
}
}
}

objSqlTran.Commit();
}
}

return buffer;
}
}
}
در پايان براي تكميل بحث مي‌توان به مقاله‌ي مرجع زير مراجعه كرد:
FILESTREAM Storage in SQL Server 2008