تولید اعداد تصادفی واقعی و امن در SQL Server:RAND() crypt_gen_random ,
تولید اعداد تصادفی در SQL Server میتواند چالشبرانگیز باشد، به خصوص زمانی که نیاز به توالیهای واقعاً تصادفی و غیرتکراری داریم. تابع داخلی RAND() اغلب انتظارات را برآورده نمیکند، زیرا در بسیاری از سناریوها، اعداد مشابهی را تولید میکند که برای کاربردهایی مانند شبیهسازی، تولید دادههای آزمایشی یا انتخاب تصادفی ردیفها مناسب نیستند. این موضوع به دلیل نحوه عملکرد RAND() و نیاز آن به یک مقدار اولیه (seed) برای آغاز توالی است. اگر مقدار seed مشخص نشود یا در یک batch یکسان فراخوانی شود، خروجیها قابل پیشبینی و تکراری خواهند بود. برای غلبه بر این محدودیت و تولید اعداد کاملاً تصادفی، باید از توابع پیشرفتهتر و تکنیکهای خاصی در SQL Server استفاده کنیم.
تابع RAND() در SQL Server به ازای هر اتصال (connection) یا در یک batch تراکنش، تنها یک بار مقدار اولیه (seed) میگیرد. این بدان معناست که اگر شما RAND() را چندین بار در یک کوئری یا batch فراخوانی کنید، خروجی آن برای هر فراخوانی یکسان خواهد بود، مگر اینکه صراحتاً یک seed متفاوت به آن بدهید. این رفتار، آن را برای تولید توالیهای تصادفی مستقل در یک مجموعه داده بزرگ نامناسب میسازد. برای مثال، کد زیر تنها یک عدد تصادفی تولید کرده و آن را برای تمام سطرها تکرار میکند:
SELECT RAND()
GO
SELECT RAND()
GO
SELECT RAND(1)
GO
SELECT RAND(1)
GO
SELECT RAND()
برای رسیدن به توالیهای تصادفی متفاوت برای هر سطر در یک کوئری، میتوانیم از یک تابع تعریف شده توسط کاربر (UDF) استفاده کنیم که از یک مقدار seed پویا بهره میبرد. اولین رویکرد، استفاده از RAND() درون یک تابع است که انتظار میرود هر بار که فراخوانی میشود، یک مقدار جدید تولید کند، اما همچنان با چالشهای مشابهی روبرو است:
CREATE FUNCTION dbo.GetRandomNumber_Attempt1()
RETURNS FLOAT
AS
BEGIN
RETURN RAND();
END;
GO
SELECT dbo.GetRandomNumber_Attempt1();
GO
SELECT dbo.GetRandomNumber_Attempt1();
این روش نیز معمولاً در یک batch یکسان، همان عدد را تولید میکند. برای اینکه هر فراخوانی تابع یک عدد تصادفی منحصر به فرد تولید کند، باید هر بار RAND() را با یک seed جدید مقداردهی کنیم. یک راه حل رایج، استفاده از NEWID() به عنوان seed است، که یک شناسه منحصر به فرد جهانی (GUID) تولید میکند و میتواند به عنوان یک seed منحصر به فرد برای RAND() عمل کند.
CREATE FUNCTION dbo.GetRandomNumber_Attempt2()
RETURNS FLOAT
AS
BEGIN
RETURN RAND(CHECKSUM(NEWID()));
END;
GO
SELECT dbo.GetRandomNumber_Attempt2() AS RandomValue;
GO
SELECT dbo.GetRandomNumber_Attempt2() AS RandomValue;
این رویکرد با استفاده از CHECKSUM(NEWID()) به عنوان seed برای RAND()، باعث میشود هر بار که تابع فراخوانی میشود، یک seed جدید داشته باشد. با این حال، حتی این روش نیز محدودیتهایی دارد؛ اگر تابع در یک کوئری که چندین سطر را برمیگرداند (مثلاً در یک SELECT با جدول بزرگ) به ازای هر سطر فراخوانی شود، ممکن است باز هم توالیهایی تکراری تولید کند، زیرا NEWID() و RAND() ممکن است در یک batch تراکنش به صورت یکسان عمل کنند.
برای تولید اعداد تصادفی واقعی و از نظر رمزنگاری امن، SQL Server تابع CRYPT_GEN_RANDOM() را ارائه میدهد. این تابع، برخلاف RAND()، یک توالی تصادفی قدرتمند و غیرقابل پیشبینی تولید میکند که برای کاربردهای امنیتی و هر جایی که نیاز به “تصادفی بودن واقعی” است، ایدهآل میباشد. CRYPT_GEN_RANDOM() یک مقدار باینری تصادفی را برمیگرداند که میتوان آن را به انواع دیگر داده تبدیل کرد. برای ایجاد یک تابع که اعداد تصادفی اعشاری بین 0 و 1 (مشابه RAND()) را تولید کند، میتوانیم از آن به این شکل بهره ببریم:
CREATE FUNCTION dbo.GetTrulyRandomNumber()
RETURNS FLOAT
AS
BEGIN
RETURN CONVERT(FLOAT, CRYPT_GEN_RANDOM(8)) / 0xFFFFFFFFFFFFFFFF;
END;
GO
SELECT dbo.GetTrulyRandomNumber() AS TrulyRandomValue;
در این تابع، CRYPT_GEN_RANDOM(8) یک مقدار باینری 8 بایتی تصادفی تولید میکند. سپس این مقدار به FLOAT تبدیل شده و بر بزرگترین عدد 64 بیتی ممکن (0xFFFFFFFFFFFFFFFF یا 18,446,744,073,709,551,615) تقسیم میشود تا یک عدد اعشاری بین 0 و 1 به دست آید. این روش، قویترین و قابل اطمینانترین راه برای تولید اعداد تصادفی در SQL Server است و برای سناریوهایی که نیاز به تصادفی بودن بالایی دارند، توصیه میشود.
میتوانید این تابع را در کوئریهای خود فراخوانی کنید تا در هر سطر یک عدد تصادفی منحصر به فرد و واقعی داشته باشید. برای مثال:
SELECT
Column1,
dbo.GetTrulyRandomNumber() AS RandomValue
FROM
YourTable;
این رویکرد تضمین میکند که هر فراخوانی از تابع dbo.GetTrulyRandomNumber() یک عدد تصادفی جدید و مستقل تولید کند، که این امر برای بسیاری از کاربردهای تحلیل داده، شبیهسازی و تولید دادههای آزمایشی که نیاز به عدم تکرار دارند، حیاتی است. استفاده از CRYPT_GEN_RANDOM() بهترین انتخاب برای تولید اعداد تصادفی با کیفیت بالا در SQL Server است.