آشنایی با SQL Server 2016 Row Level Security – محدودیت ها و کارایی (بخش سوم)

آشنایی با SQL Server 2016 Row Level Security – محدودیت ها و کارایی (بخش سوم)

نوشته شده توسط: سید محمد حسینی
۰۹ خرداد ۱۳۹۵
زمان مطالعه: 20 دقیقه
۵
(۱)

مقدمه

در دو مقاله قبل (بخش اول و بخش دوم) با RLS و نحوه استفاده از آن در SQL Server 2016 آشنا شدیم. در ادامه قصد دارم چند نکته را که باید پیش از استفاده از RLS و هر گونه پیاده سازی از آنها آگاهی داشته باشیم، مورد بررسی قرار دهم. با توجه به اینکه RLS در SQL Server 2016 معرفی شده است، دارای محدودیت هایی نیز هست. در ادامه قصد داریم با این محدودیت ها آشنا شده و برخی از کارهایی را که می توان برای کم کردن یا جبران این محدودیت ها انجام داد(در برخی موارد) را ارائه دهیم. البته باید این نکته را هم بگویم که برخی از این محدودیت ها موقتی هستند و با ارائه نسخه نهایی SQL Server 2016 بر طرف خواهند شد(نسخه استفاده شده در زمان نگارش CTP 2.2).

محدودیت های RLS در SQL Server 2016

  • SCHEMABINDING

همان طور که در مقالات قبل ذکر شد، تابع گزاره ای(Predicate Function) حتما باید با قید WITH SCHEMABINDING ایجاد گردد. در صورتی که این تابع بدون این تنظیم ایجاد گردد و قصد اتصال آن به سیاست امنیتی(Security Policy) را داشته باشیم، با خطای زیر مواجه خواهیم شد.
Msg 4513, Level 16
Cannot schema bind security policy ‘policy’. ‘dbo.function’ is not schema bound
این محدودیت نه تنها ما را در دسترسی به Catalog Viewها و DMVهای محلی محدود می کند، بلکه قادر به پیاده سازی منطق های امنیتی مبتنی بر جداول Lookup که در سایر بانک های اطلاعاتی ذخیره شده اند نیز نخواهیم بود – این به این معنی است که اگر ما یک لیست کنترل دسترسی ذخیره شده مرکزی داشته باشیم(در جایی دیگر)، می خواهیم با استفاده از viewها، Synonemها و یا پرسوجوهایی به این بانک اطلاعاتی مراجعه کنیم، یا داده ها و اطلاعات اصلی را به این بانک اطلاعاتی منتقل کنیم و یا مراجعات دیگری داشته باشیم.
  • Indexed Views

RLS با جداولی که دارای Indexed View هستند سازگاری ندارد. در صورتی که بخواهیم یک Indexed View بر روی جدولی که دارای سیاست امنیتی تعریف شده است ایجاد کنیم، با خطای زیر مواجه می شویم.
Msg 33266, Level 16
The index on the view ‘view’ cannot be created because the view is 
referencing table ‘table’ that is referenced by a security policy.
این همان قضیه مرغ و تخم مرغ است، در صورتی که جدولی هم به یک Indexed View ارجاع داده باشد، سیاست امنیتی نمی تواند به آن جدول تخصیص داده شود.
Msg 33265, Level 16
The security policy ‘policy’ cannot have a predicate on table ‘table’
because this table is referenced by the indexed view ‘view’.
همچنین در صورتی که قصد ایجاد سیاست امنیتی بر روی جدولی را داشته باشیم که توسط Partitioned View به آن ارجاع شده است نیز با خطاهای مشابهی مواجه خواهیم شد.
  • In-Memory OLTP

در این نسخه از SQL Server 2016(CTP 2.2) جداول In-Memory OLTP پشتیبانی نمی شوند. البته احتمال اینکه این جداول در نسخه RTM پشتیبانی شوند بسیار زیاد است. زیرا مایکروسافت قصد دارد تا ویژگی های جدید، تمامی قابلیت های موتور اصلی بانک اطلاعاتی(نظیر Columnstore) را پشتبیانی کنند
  • Change Data Capture

CDC نیز در SQL Server 2016 پشتیبانی نشده است. نسخه جاری امکان فعال سازی CDC را بر روی جدولی که سیاست امنیتی برای آن تخصیص داده شده است را می دهد، و همچنین می توان سیاست امنیتی را بر روی جدولی که CDC برای آن فعال شده است، تخصیص داد، اما به احتمال زیاد در نسخه RTM این قابلیت مسدود خواهد شد(در صورت عدم حذف نیز پشتیبانی نخواهد شد).
  • Full-Text Indexes

ایندکس های Full-Text مورد پشتیبانی قرار گرفته اند، ولی باید به یاد داشته باشید که ایندکس ها بر اساس داده های فیلتر نشده هستند. البته به رغم سیاست امنیتی تعیین شده برای جدول ممکن است در مواردی با نشتی اطلاعات مواجه شویم.

تاثیر RLS بر کارایی SQL Server

در پرسوجوهای SELECT، برای فیلتر کردن سطرها قطعا تاثیر قابل توجهی در پلان اجرایی مشاهده خواهد شد. در بیشتر موارد عملگر Left Semi Join در کنار جدول/جداولی که از تابع گزاره ای استفاده می کنند قابل مشاهده است. در زیر پلان اجرایی دو پرسوجوی *  SELECT آورده شده است. پرسوجوی اول بدون سیاست امنیتی اجرا شده است و اجرای پرسوجوی دوم به همراه فیلتر سازی در سطح سطر می باشد.
 
چیزی که از تصویر فوق می توان مشاهده کرد، این است که منطق و عملگرهای inline TVF در پلان اجرایی پرسوجوی اول وجود ندارند، همچنین بهینه کردن تابع گزاره ای جهت کمتر شدن تاثیر آن در اجرای پرسوجو می تواند به میزان بسیار زیادی اهمیت داشته باشد. این که RLS چه میزان می تواند در کارایی و حجم کاری ما تاثیر گذار باشد به عوامل گوناگون و متفاوتی وابسته است – نظیر الگوی پرسوجو، منطق استفاده شده در تابع گزاره و…
نکته قابل توجه دیگر این است که، کاربرانی که عضو sysadmin، db_owner، db_ddladmin و مالک(owner) جدول نیستند، دسترسی مستقیم به DBCC  SHOW_STATISTICS ندارند – زیرا این مسئله می تواند موجب نشت اطلاعات شود. بدیهی hست که ما باید برنامه کاربری را به طور کامل از نظر رفتار و عوامل کاهنده کارایی مورد تست قرار دهیم. در ادامه با یک مثال دیگر، میزان تاثیرات RLS بر کارایی را بیشتر بررسی خواهیم کرد.

عیب یابی RLS در SQL Server

به طور پیش فرض، dbo و sysadmin قادر به دسترسی به تمامی سطرهای جدول نیستند. در صورتی که ما نیاز به عیب یابی پرسوجوها، تکرار برخی کارها، یا حتی بازبینی معمولی اطلاعات را داشته باشیم، باید اطمینان یابیم که تابع گزاره ای اجازه این کار را به ما می دهد، یا اینکه با کاربری که دارای دسترسی کامل است با بانک اطلاعاتی کار کنیم(در کدهایی که در ادامه آورده شده است، چنین کاربری ایجاد شده است).
همچنین، امکان به وجود آمدن یک پلان اجرایی پیچیده برای یک پرسوجوی نسبتا ساده دور از انتظار نبوده و می تواند موجب سر در گمی گردد. از طرفی درک این مسئله می تواند برای کاربران مشکل ساز شود که چرا اشیاء مربوط به تابع گزاره ای در پلان اجرایی ظاهر شده اند، در حالی که هیچ تابعی یا هیچ یک از آن اشیاء در متن پرسوجو استفاده نشده اند.

نشت اطلاعات در RLS

چندین روش برای کار کردن کاربران در محدوده RLS وجود دارد. همانطور که در قبل گفته شد، ایندکس های Full Text می توانند موجب بروز مشکل شوند، ولی چندین مسئله وجود دارد که باید آنها را به خاطر داشت.
  •  Policy Managers and Collusion

همانطور که قبلا گفته شد، حتی کاربران dbo و sysadmin نیز قادر به دستیابی به تمامی اطلاعات جدول نیستند مگر اینکه صراحتا از تابع گزاره ای مجوز داشته باشند. البته، اگر کاربری مسئول مدیریت سیاست های امنیتی باشد  و امکان اعمال تغییرات در توابع مورد استفاده در سیاست ها را دارا باشد، می تواند به سادگی با اعمال تغییر در منطق به این هدف برای خود دست یابد(البته این مورد را می توان به سادگی با استفاده از تریگرهای DDL مانیتور کرد)، و یا می تواند جهت قابل مشاهده شدن سایر سطرها برای برخی کاربران با آنها تبانی کند، همچنین می تواند به سادگی سیاست امنیتی را برای مدتی موقتا غیر فعال کند(البته این کار می تواند مورد بازبینی و حسابرسی قرار گیرد). در اینجا لیست کاملی از کارهای مخربی که مدیر سیاست امنیتی می تواند انجام دهد آورده شده است.
  • CONTEXT_INFO

اگر قصد داشته باشیم که مثلا در یک برنامه وب فیلترکردن در سطح سطر را پیاده سازی کنیم به طوری که تمامی کاربران با یک نام کاربری مشترک لاگین کنند(در SQL Server) این کار را می توان از طریق ارسال اطلاعات خاص هر کاربر به ()CONTEXT_INFO انجام داد. مشکلی که در اینجا رخ می دهد این است که، در صورتی که هر کاربری توانایی اجرای پرسوجوی ad hoc را داشته باشد، می توانند از ()CONTEXT_INFO کلاهبرداری کنند.
در مثال زیر کاربر Poen می تواند اطلاعات هر کاربری را مشاهده کند..
 توجه: کدهای مورد نیاز برای ایجاد جداول، کاربران، تابع گزاره ای و سیاست امنیتی جهت اجرای این مثال و مثال های بعد، در انتهای این بخش و با عنوان کد های تکمیلی قرار داده شده است.

 EXECUTE AS USER = N'Peon';
GO
DECLARE @ci VARBINARY(128) = CONVERT(VARBINARY(128),N'Rep1');
SET CONTEXT_INFO @ci;
SELECT USER_NAME(), * FROM dbo.Accounts;
GO
REVERT;
GO
راه حل مناسب در اینجا می تواند افزودن Dynamic data masking، Column-level encryption یا انواع hashing/obfuscation/salting برای نام کاربری Rep1 باشد، در این صورت کاربر مخرب نمی تواند از محتویات ()CONTEXT_INFO اطلاع یابد. ولی در حالت کلی، می بایست دسترسی به این داده ها را در تمامی SPها و در درون کد برنامه کنترل کنیم، حتی اگر دسترسی مستقیم به پرسوجوهای ad hoc وجود نداشته باشد.
  •  Clever ad hoc queries

در برخی مواقع که کاربر به سطرها دسترسی ندارد، می تواند پرسوجو را به گونه ای بنویسد که اطلاعات مختصری را در مورد سطرها به دست آورد. در مثال زیر کاربر Poen می تواند به دست آورد که کدام یک از کاربران ?Rep دارای رکوردی با شرط AnnualFees>75000$ است.

 EXECUTE AS USER = N'Peon';
GO
DECLARE @i INT = 1;
BEGIN TRY
SELECT *
FROM dbo.Accounts
WHERE CASE WHEN RepID = @i THEN
CASE WHEN AnnualFees > 75000
THEN CONVERT(INT, 'x') -- designed to raise an exception
END
END = 1;
END TRY
BEGIN CATCH
PRINT N'Rep ' + RTRIM(@i) + N' has an account with fees > $75,000.';
END CATCH
GO
REVERT;
GO
در صورتی که یک حلقه ایجاد کنیم و در آن i@ را افزایش دهیم، با اجرای این کد، برای هر یک از کاربران ?Rep که دارای رکوردی با شرط AnnualFees>75000$ است اطلاعات مختصری چاپ می شود. این کد اجرا می شود زیرا برخی از عبارت ها پیش از اینکه فیلتر کردن در سطح سطر اعمال شود، ارزیابی می شوند. بنابراین با تکرار و کمی تلاش می توان مواردی را به دست آورد که اطلاعات کامل تری در مورد سایر سطرهای جدول در اختیار ما قرار دهد(البته کاربران مخرب قطعا این تکرار و تلاش را دارند) – این مثال بسیار خوب است، فرض کنید در جدول HR که شما می توانید میزان حقوق خود را ببینید؛ با استفاده از پرسوجوهای ad hoc و زمان کافی و کمی صبر، این باگ می تواند به شما کمک کند که میزان حقوق هر کسی را به دست آورید.
مسلما، کاربر Poen در ابتدا مجوز SELECT را نداشته است، اما به یاد داشته باشید که هر یک از کاربران ?Rep می توانند حمله ای این چنینی را پیاده سازی کنند. امیدوارم که در نسخه RTM این مشکل برطرف گردد.
  • Inserting invalid rows

نکته مهم دیگر در مورد RLS(البته تا نسخه جاری)، این است که مجوز نوشتن توسط سیاست امنیتی مسدود نشده است. بنابراین در صورتی که من بتوانم در جدول سطری درج کنم، ممکن است به طور ناخودآگاه(و یا حتی آگاهانه) رکوردی را برای سایر کاربران ?Rep درج کنم.

 GRANT INSERT, UPDATE ON dbo.Accounts TO Rep1;
GO
EXEC('INSERT dbo.Accounts(AccountID,AnnualFees,RepID)
VALUES(99,50000,2);') AS USER = N'Rep1';
GO
در کد فوق من توانسته ام سطری را درج کنم بدون اینکه بتوانم آن را ببینم. با استفاده از کد زیر می توان این مسئله را بررسی کرد:
 EXEC('SELECT * FROM dbo.Accounts WHERE AccountID = 99;') AS USER = N'Rep1';
EXEC('SELECT * FROM dbo.Accounts WHERE AccountID = 99;') AS USER = N'Rep2';
GO
این مسئله بسیار کوچکیست، ولی جای بررسی بیشتری را دارد. در محیط های بسیار حساس، درج رکوردهایی بجای سایر کاربران، می تواند مشکلات بسیار جدی را ایجاد کند. در حال حاضر، برای ایمن کردن جداول از درج های ناخواسته یا نادرست، باید از Check Constraintها یا INSERT Trigger و یا با کنترل عملیات درج در SPها در جهت رسیدن به منطق استفاده شده در تابع گزاره ای استفاده کنیم.
البته تا این نسخه که ما مورد بررسی قرار داده ایم، سایر DMLها محافظت شده هستند. برای مثال، در کد زیر من نمی توانم سطری را که قادر به دیدن آن نیستم، بروزرسانی کرده و یا حذف کنم.
 EXEC('UPDATE dbo.Accounts SET AnnualFees*=2 WHERE AccountID = 99;') AS USER = N'Rep1';
EXEC('SELECT * FROM dbo.Accounts WHERE AccountID = 99;') AS USER = N'Susan';
GO

کدهای تکمیلی

 CREATE TABLE dbo.AccountReps
(
RepID INT,
SQLPrincipalName SYSNAME,
CONSTRAINT PK_AccountReps PRIMARY KEY(RepID),
CONSTRAINT UQ_PrincipalName UNIQUE(SQLPrincipalName)
);
GO
CREATE USER Rep1 WITHOUT LOGIN;
CREATE USER Rep2 WITHOUT LOGIN;
CREATE USER Rep3 WITHOUT LOGIN;
CREATE USER Peon WITHOUT LOGIN;
CREATE USER Susan WITHOUT LOGIN;
CREATE ROLE RepManagers;
ALTER ROLE RepManagers ADD MEMBER Susan;
GO
INSERT dbo.AccountReps(RepID, SQLPrincipalName)
VALUES(1, N'Rep1'),(2, N'Rep2'),(3, N'Rep3');
GO
CREATE TABLE dbo.Accounts
(
AccountID INT,
AnnualFees INT,
RepID INT NOT NULL,
CONSTRAINT PK_Accounts PRIMARY KEY(AccountID),
CONSTRAINT FK_AccountReps FOREIGN KEY(RepID)
REFERENCES dbo.AccountReps(RepID)
);
GO
INSERT dbo.Accounts(AccountID,AnnualFees,RepID)
VALUES (1,55000,1),(2,25000,1),(3,65000,1),(4,35000,2),(5,82000,2);
GO
GRANT SELECT ON dbo.Accounts TO Peon, Rep1, Rep2, Rep3, Susan;
GRANT SELECT ON dbo.AccountReps TO Peon, Rep1, Rep2, Rep3, Susan;
GO
CREATE USER sqlapp WITHOUT LOGIN;
GRANT SELECT ON dbo.Accounts TO sqlapp;
GO
--------------------------------------------------
CREATE FUNCTION dbo.LimitAccountAccess(@RepID INT)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
SELECT [Go] = 1
FROM dbo.AccountReps
WHERE (RepID = @RepID
AND SQLPrincipalName = CONVERT(SYSNAME, CONTEXT_INFO())
) OR IS_MEMBER(N'RepManagers') = 1
);
GO
CREATE SECURITY POLICY AccountAndRepPolicy
ADD FILTER PREDICATE dbo.LimitAccountAccess(RepID) ON dbo.AccountReps,
ADD FILTER PREDICATE dbo.LimitAccountAccess(RepID) ON dbo.Accounts
WITH (STATE = ON);
GO
--------------------------------------------------
EXECUTE AS USER = N'sqlapp';
GO
DECLARE @ci VARBINARY(128) = CONVERT(VARBINARY(128),N'Rep1');
SET CONTEXT_INFO @ci;
SELECT USER_NAME(), * FROM dbo.Accounts;
GO
REVERT;
GO

بررسی میزان تاثیر RLS بر کارایی SQL Server

در اینجا قصد نداریم که سناریوی مربوط به تابع گزاره ای و سیاست امنیتی را مورد بررسی قرار دهیم، بلکه فقط می خواهیم با انجام یک آزمایش، کارایی SQL Server را بدون RLS و با استفاده از RLS مقایسه کنیم. کدهای زیر جداول، ایندکس ها و داده های مورد نیاز برای انجام آزمایش را ایجاد می کند:
 -- Create SampleUser table
CREATE TABLE [dbo].[SampleUser](
[UserID] [int] NOT NULL PRIMARY KEY,
[Username] [varchar](30)
)
GO
-- Create SampleData table and foreign key to SampleUser table
CREATE TABLE [dbo].[SampleData](
[RowKey] [int] NOT NULL PRIMARY KEY,
[CreateDate] [datetime] NOT NULL,
[OtherDate] [datetime] NOT NULL,
[VarcharColumn] [varchar](20) NULL,
[IntColumn] [int] NULL,
[FloatColumn] [float] NULL,
[UserID] [int] NOT NULL
)
GO
ALTER TABLE [dbo].[SampleData] WITH CHECK
ADD CONSTRAINT [FK_SampleData_SampleUser]
FOREIGN KEY([UserID])
REFERENCES [dbo].[SampleUser] ([UserID])
GO
-- Load SampleUser table
DECLARE @val INT
SELECT @val=1
WHILE @val < 51
BEGIN
INSERT INTO SampleUser VALUES (@val,'User' + cast(@val AS VARCHAR))
SELECT @val=@val+1
END
GO
-- Load SampleData table
DECLARE @val INT
SELECT @val=1
WHILE @val < 5000000
BEGIN
INSERT INTO SampleData
VALUES
(@val,
getdate(),
DATEADD(DAY, ABS(CHECKSUM(NEWID()) % 365),'2015-01-01'),
'TEST' + cast(round(rand()*100,0) AS VARCHAR),
round(rand()*100000,0),
round(rand()*10000,2),
round(rand()*49,0)+1)
SELECT @val=@val+1
END
GO
-- create indexes
CREATE NONCLUSTERED INDEX [IX_SampleData_CreateDate] ON [dbo].[SampleData] ([CreateDate] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_SampleData_UserID] ON [dbo].[SampleData] ([UserID] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_SampleUser_Username] ON [dbo].[SampleUser] ([Username] ASC)
GO
در ادامه، کاربران و مجوزهای آنها را تعریف می کنیم.

-- sysadmin user
CREATE LOGIN [test_sa] WITH PASSWORD=N'#######', DEFAULT_DATABASE=[master],
CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
ALTER SERVER ROLE [sysadmin] ADD MEMBER [test_sa]
GO
-- regular user
CREATE LOGIN [User10] WITH PASSWORD=N'#######', DEFAULT_DATABASE=[master],
CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
USE [TestDB]
GO
CREATE USER [User10] FOR LOGIN [User10]
GO
USE [TestDB]
GO
ALTER ROLE [db_datareader] ADD MEMBER [User10]
GO
حال، پیش از اینکه RLS را برای این جداول فعال کنیم، پرسوجوهای زیر را برای کاربران مشخص شده اجرا می کنیم و نتایج حاصل شده از اجرای این پرسوجوها در SQL Query Profiler را ثبت می کنیم.
 -- run using test_sa account
-- query 1
SELECT *
FROM SampleData d
INNER JOIN SampleUser u on d.UserID=u.UserID
WHERE u.Username = 'User10'
GO
-- query 2
SELECT *
FROM SampleData d
WHERE CreateDate > '2016-02-03 19:59:47.560'
-- run using User10 account
-- query 3
SELECT *
FROM SampleData d
INNER JOIN SampleUser u on d.UserID=u.UserID
WHERE u.Username = user_name()
GO
-- query 4
SELECT *
FROM SampleData d
INNER JOIN SampleUser u on d.UserID=u.UserID
WHERE u.Username = user_name()
AND CreateDate > '2016-02-03 19:59:47.560'
GO
سپس، RLS را با تعریف تابع گزاره ای و سیاست امنیتی مورد نظر ایجاد و فعال می کنیم.

 CREATE FUNCTION dbo.fn_securitypredicateUser (@UserID int)
RETURNS TABLE
WITH Schemabinding
AS
RETURN SELECT 1 AS [fn_securitypredicateUser_result]
FROM dbo.SampleUser SU
WHERE (SU.UserID=@UserID AND SU.Username = user_name())
OR IS_SRVROLEMEMBER(N'sysadmin') = 1
GO
CREATE SECURITY POLICY fn_security
ADD FILTER preDICATE dbo.fn_securitypredicateUser(UserID)
ON dbo.SampleData
GO


حال، مشابه قبل عمل کرده و پرسوجوهای زیر را دوباره و پس از فعال شدن RLS اجرا کرده و نتایج حاصل شده از اجرای این پرسوجوها در SQL Query Profiler را ثبت می کنیم.
 -- run using test_sa account
-- query 1
SELECT *
FROM SampleData d
INNER JOIN SampleUser u on d.UserID=u.UserID
WHERE u.Username = 'User10'
GO
-- query 2
SELECT *
FROM SampleData d
WHERE CreateDate > '2016-02-03 19:59:47.560'
-- run using User10 account
-- query 3
SELECT *
FROM SampleData d
INNER JOIN SampleUser u on d.UserID=u.UserID
WHERE u.Username = user_name()
GO
-- query 4
SELECT *
FROM SampleData d
INNER JOIN SampleUser u on d.UserID=u.UserID
WHERE u.Username = user_name()
AND CreateDate > '2016-02-03 19:59:47.560'
GO
در جدول زیر نتایج به دست آمده از اجرای پرسوجوهای فوق برای دو کاربر test_sa و User10 در دو حالتی که RLS فعال و غیر فعال است، نشان داده شده است.
اگر به آمار کاربری که دارای مجوز sysadmin است(کاربر test_sa و پرسوجوهای ۱ و ۲) نگاه کنیم، صرف نظر از اینکه RLS فعال است یا خیر، تفاوت بیشتر در میزان CPU مصرفی می باشد. البته در محیط های واقعی، کاربر با مجوز sysadmin کمتر مورد استفاده قرار می گیرد
اگر به آمار کاربر عادی(کاربر User10 و پرسوجوهای ۳ و ۴) نگاه کنیم، نتایج کمی متفاوت است. در پرسوجوی ۳، میزان CPU مصرفی و زمان اجرا و تعداد عملیات خواندن دارای تفاوت چشم گیری هستند. علت این موضوع این است که با فعال بودن RLS، تابع گزاره ای به ازای تک تک سطرهای جدول اجرا می شود و این یعنی اسکن کردن تمامی جدول(البته معمولا این گونه پرسوجو ها از طرف برنامه کاربردی کمتر صادر می شوند). پرسوجوی چهام یک پرسوجوی استاندارد است که معمولا از طرف برنامه کاربردی تقاضا می شود(پرسوجوی SELECT به همراه عبارت WHERE). همانطور که مشخص است در این پرسوجو نیز یک سربار اضافه به علت اجرا شدن تابع گزاره ای برای سطرهای خروجی وجود دارد.
در نهایت می توان نتیجه گرفت که این قابلیت جدید، از این نظر که کنترل دسترسی به داده ها را می توان به سادگی و بدون هر گونه تغییری در پرسوجوهای جاری و برنامه کاربردی و حتی بدون اینکه کاربر اطلاعی از آن داشته باشد اعمال کرد، می تواند بسیار مفید باشد. ولی در کنار منافع به دست آمده، مسئله اصلی، میزان سربار اضافه ای است که این قابلیت جدید به بانک اطلاعاتی ما ممکن است تحمیل نماید

چه رتبه ای می‌دهید؟

میانگین ۵ / ۵. از مجموع ۱

اولین نفر باش

title sign
معرفی نویسنده
سید محمد حسینی
مقالات
11 مقاله توسط این نویسنده
محصولات
0 دوره توسط این نویسنده
سید محمد حسینی
پروفایل نویسنده
title sign
دیدگاه کاربران

هر روز یک ایمیل، هر روز یک درس
آموزش SQL Server بصورت رایگان
همین حالا فرم زیر را تکمیل کنید
دانلود رایگان جلسه اول
نیک آموز علاوه بر آموزش، پروژه‌های بزرگ در حوزه هوش تجاری و دیتا انجام می‌دهد.
close-link