จำลองฟังก์ชันสเกลาร์ที่ผู้ใช้กำหนดในลักษณะที่ไม่ได้ป้องกันการขนาน


12

ฉันพยายามดูว่ามีวิธีการหลอกลวง SQL Server ให้ใช้แผนบางอย่างสำหรับแบบสอบถามหรือไม่

1. สภาพแวดล้อม

ลองนึกภาพคุณมีข้อมูลบางอย่างที่ใช้ร่วมกันระหว่างกระบวนการที่แตกต่างกัน สมมติว่าเรามีผลการทดสอบบางอย่างซึ่งใช้พื้นที่มาก จากนั้นสำหรับแต่ละขั้นตอนเรารู้ว่าต้องการใช้ปี / เดือนใด

if object_id('dbo.SharedData') is not null
    drop table SharedData

create table dbo.SharedData (
    experiment_year int,
    experiment_month int,
    rn int,
    calculated_number int,
    primary key (experiment_year, experiment_month, rn)
)
go

ตอนนี้สำหรับทุกกระบวนการเรามีพารามิเตอร์ที่บันทึกไว้ในตาราง

if object_id('dbo.Params') is not null
    drop table dbo.Params

create table dbo.Params (
    session_id int,
    experiment_year int,
    experiment_month int,
    primary key (session_id)
)
go

2. ทดสอบข้อมูล

ลองเพิ่มข้อมูลทดสอบ:

insert into dbo.Params (session_id, experiment_year, experiment_month)
select 1, 2014, 3 union all
select 2, 2014, 4 
go

insert into dbo.SharedData (experiment_year, experiment_month, rn, calculated_number)
select
    2014, 3, row_number() over(order by v1.name), abs(Checksum(newid())) % 10
from master.dbo.spt_values as v1
    cross join master.dbo.spt_values as v2
go

insert into dbo.SharedData (experiment_year, experiment_month, rn, calculated_number)
select
    2014, 4, row_number() over(order by v1.name), abs(Checksum(newid())) % 10
from master.dbo.spt_values as v1
    cross join master.dbo.spt_values as v2
go

3. การดึงผลลัพธ์

ตอนนี้การรับผลการทดสอบทำได้ง่ายมากโดย@experiment_year/@experiment_month:

create or alter function dbo.f_GetSharedData(@experiment_year int, @experiment_month int)
returns table
as
return (
    select
        d.rn,
        d.calculated_number
    from dbo.SharedData as d
    where
        d.experiment_year = @experiment_year and
        d.experiment_month = @experiment_month
)
go

แผนดีและขนานกัน:

select
    calculated_number,
    count(*)
from dbo.f_GetSharedData(2014, 4)
group by
    calculated_number

แบบสอบถาม 0 แผน

ป้อนคำอธิบายรูปภาพที่นี่

4. ปัญหา

แต่จะทำให้การใช้งานของข้อมูลบิตทั่วไปมากขึ้นผมต้องการที่จะมีฟังก์ชั่นอื่น dbo.f_GetSharedDataBySession(@session_id int)- ดังนั้นวิธีที่ตรงไปตรงมาก็คือการสร้างฟังก์ชันสเกลาร์, การแปล@session_id-> @experiment_year/@experiment_month:

create or alter function dbo.fn_GetExperimentYear(@session_id int)
returns int
as
begin
    return (
        select
            p.experiment_year
        from dbo.Params as p
        where
            p.session_id = @session_id
    )
end
go

create or alter function dbo.fn_GetExperimentMonth(@session_id int)
returns int
as
begin
    return (
        select
            p.experiment_month
        from dbo.Params as p
        where
            p.session_id = @session_id
    )
end
go

และตอนนี้เราสามารถสร้างฟังก์ชั่นของเรา:

create or alter function dbo.f_GetSharedDataBySession1(@session_id int)
returns table
as
return (
    select
        d.rn,
        d.calculated_number
    from dbo.f_GetSharedData(
        dbo.fn_GetExperimentYear(@session_id),
        dbo.fn_GetExperimentMonth(@session_id)
    ) as d
)
go

แบบสอบถาม 1 แผน

ป้อนคำอธิบายรูปภาพที่นี่

แผนคือเหมือนเดิมยกเว้นมันแน่นอนไม่ขนานเพราะฟังก์ชั่นสเกลาร์ที่มีประสิทธิภาพทำให้การเข้าถึงข้อมูลอนุกรมแผนทั้งหมด

ดังนั้นฉันจึงได้ลองวิธีที่แตกต่างหลายอย่างเช่นการใช้แบบสอบถามย่อยแทนฟังก์ชั่นสเกลาร์:

create or alter function dbo.f_GetSharedDataBySession2(@session_id int)
returns table
as
return (
    select
        d.rn,
        d.calculated_number
    from dbo.f_GetSharedData(
       (select p.experiment_year from dbo.Params as p where p.session_id = @session_id),
       (select p.experiment_month from dbo.Params as p where p.session_id = @session_id)
    ) as d
)
go

แบบสอบถาม 2 แผน

ป้อนคำอธิบายรูปภาพที่นี่

หรือการใช้ cross apply

create or alter function dbo.f_GetSharedDataBySession3(@session_id int)
returns table
as
return (
    select
        d.rn,
        d.calculated_number
    from dbo.Params as p
        cross apply dbo.f_GetSharedData(
            p.experiment_year,
            p.experiment_month
        ) as d
    where
        p.session_id = @session_id
)
go

แบบสอบถาม 3 แผน

ป้อนคำอธิบายรูปภาพที่นี่

แต่ฉันไม่สามารถหาวิธีเขียนแบบสอบถามนี้ให้ดีเท่าที่ใช้ฟังก์ชันสเกลาร์ได้

คู่ของความคิด:

  1. โดยทั่วไปสิ่งที่ฉันต้องการคือการสามารถบอก SQL Server เพื่อคำนวณค่าบางอย่างล่วงหน้าแล้วส่งต่อไปเป็นค่าคงที่
  2. สิ่งที่อาจเป็นประโยชน์คือถ้าเรามีคำแนะนำที่เป็นรูปธรรมบางอย่าง ฉันได้ตรวจสอบตัวแปรสองตัว (หลายคำสั่ง TVF หรือ cte พร้อมด้านบน) แต่ไม่มีแผนใดดีเท่ากับรุ่นที่มีฟังก์ชันสเกลาร์จนถึงปัจจุบัน
  3. ฉันรู้เกี่ยวกับการปรับปรุงของ SQL Server 2017 - Froid: การเพิ่มประสิทธิภาพของโปรแกรมที่จำเป็นในฐานข้อมูลเชิงสัมพันธ์ฉันไม่แน่ใจว่ามันจะช่วยได้อย่างไร มันคงจะดีถ้าได้พิสูจน์ความผิดที่นี่

ข้อมูลเพิ่มเติม

ฉันกำลังใช้ฟังก์ชั่น (แทนที่จะเลือกข้อมูลโดยตรงจากตาราง) เพราะมันง่ายต่อการใช้งานในแบบสอบถามที่แตกต่างกันซึ่งมักจะมี@session_idพารามิเตอร์

ฉันถูกขอให้เปรียบเทียบเวลาดำเนินการจริง ในกรณีนี้โดยเฉพาะ

  • แบบสอบถาม 0 ทำงานประมาณ ~ 500ms
  • แบบสอบถาม 1 ทำงานประมาณ ~ 1500ms
  • แบบสอบถาม 2 ทำงานประมาณ ~ 1500ms
  • แบบสอบถาม 3 ทำงานประมาณ ~ 2000ms

แผน # 2 มีการสแกนดัชนีแทนการค้นหาซึ่งจะถูกกรองโดยเพรดิเคตบนลูปซ้อนกัน แผน # 3 นั้นไม่เลว แต่ก็ยังทำงานได้มากขึ้นและทำงานช้าลงตามแผน # 0

สมมติว่าdbo.Paramsมีการเปลี่ยนแปลงน้อยมากและมักจะมีประมาณ 1-200 แถวไม่เกินสมมติว่ามี 2,000 รายการที่คาดหวัง ตอนนี้มีประมาณ 10 คอลัมน์และฉันไม่คิดว่าจะเพิ่มคอลัมน์บ่อยเกินไป

จำนวนแถวใน Params ไม่ได้รับการแก้ไขดังนั้นสำหรับทุก@session_idแถวจะมีแถว จำนวนคอลัมน์ที่ไม่มีการแก้ไขเป็นหนึ่งในเหตุผลที่ฉันไม่ต้องการโทรdbo.f_GetSharedData(@experiment_year int, @experiment_month int)จากทุกที่ดังนั้นฉันสามารถเพิ่มคอลัมน์ใหม่ในแบบสอบถามนี้ภายใน ฉันยินดีที่จะรับฟังความคิดเห็น / คำแนะนำเกี่ยวกับสิ่งนี้แม้ว่าจะมีข้อ จำกัด


แผนคิวรีที่มี Froid จะคล้ายกับคิวรี 2 ด้านบนดังนั้นใช่มันจะไม่นำคุณไปสู่โซลูชันที่คุณต้องการบรรลุในกรณีนี้
Karthik

คำตอบ:


13

คุณไม่สามารถบรรลุสิ่งที่คุณต้องการใน SQL Server ได้อย่างปลอดภัยในวันนี้เช่นในคำสั่งเดียวและด้วยการประมวลผลแบบขนานภายในข้อ จำกัด ที่วางไว้ในคำถาม

ดังนั้นคำตอบง่ายๆของฉันคือไม่มี ส่วนที่เหลือของคำตอบนี้ส่วนใหญ่เป็นการอภิปรายว่าทำไมในกรณีที่เป็นที่สนใจ

เป็นไปได้ที่จะได้รับแผนคู่ขนานตามที่ระบุไว้ในคำถาม แต่มีสองสายพันธุ์หลักซึ่งไม่เหมาะสำหรับความต้องการของคุณ:

  1. การวนซ้ำซ้อนกันที่สัมพันธ์กันโดยมี robin แบบกลมกระจายสายน้ำในระดับบนสุด ระบุว่าแถวเดียวรับประกันได้ว่าจะมาจากParamsสำหรับเฉพาะsession_idค่าด้านในจะทำงานในหัวข้อเดียวแม้ว่ามันจะถูกทำเครื่องหมายด้วยไอคอนขนาน นี่คือเหตุผลที่แผนขนาน3ไม่ทำงานเช่นกัน มันอยู่ในความเป็นจริงอนุกรม

  2. ทางเลือกอื่น ๆ สำหรับการขนานอิสระที่ด้านในของลูปซ้อนกัน อิสระที่นี่หมายความว่าเธรดจะเริ่มทำงานที่ด้านในและไม่เพียง แต่เธรดเดียวกับที่กำลังดำเนินการด้านนอกของลูปซ้อนกัน SQL Server สนับสนุนการวนซ้ำกันของลูปซ้อนภายในเท่านั้นเมื่อมีการรับประกันว่าเป็นหนึ่งแถวด้านนอกและไม่มีพารามิเตอร์เข้าร่วมที่สัมพันธ์กัน ( แผน 2 )

ดังนั้นเรามีทางเลือกของแผนขนานที่เป็นอนุกรม (เนื่องจากหนึ่งเธรด) ที่มีค่าสหสัมพันธ์ที่ต้องการ หรือแผนขนานด้านในที่ต้องสแกนเนื่องจากไม่มีพารามิเตอร์ที่ต้องค้นหา (นอกเหนือจาก: มันควรจะได้รับอนุญาตให้ขับรถคู่ขนานด้านในโดยใช้พารามิเตอร์ที่สัมพันธ์กันเพียงชุดเดียวแต่ไม่เคยนำมาใช้อาจเป็นเพราะเหตุผลที่ดี)

คำถามทั่วไปคือทำไมเราต้องมีพารามิเตอร์ที่เกี่ยวข้องทั้งหมด เหตุใด SQL Server จึงไม่สามารถค้นหาค่าสเกลาร์ที่จัดเตรียมโดยตรงเช่นแบบสอบถามย่อยได้โดยตรง

SQL Server สามารถ 'ค้นหาดัชนี' โดยใช้การอ้างอิงแบบสเกลาร์อย่างง่ายเท่านั้นเช่นการอ้างอิงค่าคงที่ตัวแปรคอลัมน์หรือนิพจน์ (เพื่อให้ผลลัพธ์ของฟังก์ชันสเกลาร์สามารถมีคุณสมบัติได้) แบบสอบถามย่อย (หรือสิ่งก่อสร้างที่คล้ายกันอื่น ๆ ) นั้นซับซ้อนเกินไป (และอาจไม่ปลอดภัย) ที่จะผลักดันให้เข้าสู่เครื่องมือจัดเก็บข้อมูลทั้งหมด ดังนั้นจำเป็นต้องใช้ตัวดำเนินการแผนแบบสอบถามแยกต่างหาก นี่คือเทิร์นที่ต้องใช้ความสัมพันธ์ซึ่งหมายความว่าไม่มีการเรียงคู่ขนานที่คุณต้องการ

สรุปแล้วปัจจุบันยังไม่มีวิธีแก้ปัญหาที่ดีไปกว่าวิธีการกำหนดค่าการค้นหาให้กับตัวแปรแล้วใช้วิธีนั้นในพารามิเตอร์ฟังก์ชันในคำสั่งแยกกัน

ตอนนี้คุณอาจมีข้อควรพิจารณาในท้องถิ่นที่เฉพาะเจาะจงซึ่งหมายถึงการแคชค่าปัจจุบันของปีและเดือนที่SESSION_CONTEXTคุ้มค่าเช่น:

SELECT FGSD.calculated_number, COUNT_BIG(*)
FROM dbo.f_GetSharedData
(
    CONVERT(integer, SESSION_CONTEXT(N'experiment_year')), 
    CONVERT(integer, SESSION_CONTEXT(N'experiment_month'))
) AS FGSD
GROUP BY FGSD.calculated_number;

แต่นี่เป็นหมวดหมู่ของการแก้ปัญหา

ในทางกลับกันหากประสิทธิภาพการรวมมีความสำคัญหลักคุณสามารถลองผสานกับฟังก์ชั่นอินไลน์และสร้างดัชนี columnstore (หลักหรือรอง) บนตาราง คุณอาจพบประโยชน์ของการจัดเก็บแบบคอลัมน์การประมวลผลแบบแบทช์และการกดลงรวมจะให้ประโยชน์มากกว่าการค้นหาแบบขนานในโหมดแถว

แต่ระวังฟังก์ชั่นสเกลาร์ T-SQL โดยเฉพาะอย่างยิ่งกับที่เก็บข้อมูลคอลัมน์เนื่องจากมันง่ายที่จะจบลงด้วยฟังก์ชั่นที่ถูกประเมินต่อแถวในตัวกรองแถวโหมดแยกต่างหาก โดยทั่วไปค่อนข้างยุ่งยากในการรับประกันจำนวนครั้งที่ SQL Server จะเลือกประเมินสเกลาร์และไม่ควรลองใช้


ขอบคุณพอลคำตอบที่ดี! ฉันคิดเกี่ยวกับการใช้session_contextแต่ฉันคิดว่ามันเป็นความคิดที่บ้าเกินไปสำหรับฉันและฉันไม่แน่ใจว่ามันจะเข้ากับสถาปัตยกรรมปัจจุบันของฉันได้อย่างไร สิ่งที่จะเป็นประโยชน์แม้ว่าอาจเป็นคำใบ้บางอย่างที่ฉันสามารถใช้เพื่อให้เครื่องมือเพิ่มประสิทธิภาพทราบว่าควรปฏิบัติต่อผลลัพธ์ของแบบสอบถามย่อยเช่นการอ้างอิงแบบสเกลาร์อย่างง่าย
Roman Pekar

8

เท่าที่ฉันรู้รูปร่างแผนที่คุณต้องการเป็นไปไม่ได้ด้วย T-SQL ดูเหมือนว่าคุณต้องการรูปร่างแผนดั้งเดิม (แบบสอบถาม 0 แผน) ด้วยแบบสอบถามย่อยจากฟังก์ชั่นของคุณถูกนำไปใช้เป็นตัวกรองโดยตรงกับการสแกนดัชนีคลัสเตอร์ คุณจะไม่ได้รับแผนคิวรีแบบนั้นถ้าคุณไม่ใช้ตัวแปรโลคอลเพื่อเก็บค่าส่งคืนของฟังก์ชันสเกลาร์ การกรองจะถูกนำไปใช้แทนการเข้าร่วมลูปซ้อนกัน มีสามวิธีที่แตกต่างกัน (จากมุมมองแบบคู่ขนาน) ที่สามารถใช้การรวมแบบวนซ้ำได้:

  1. แผนทั้งหมดเป็นแบบอนุกรม สิ่งนี้ไม่เป็นที่ยอมรับสำหรับคุณ นี่คือแผนการที่คุณได้รับสำหรับแบบสอบถาม 1
  2. การเข้าร่วมแบบวนซ้ำจะทำงานเป็นอนุกรม ฉันเชื่อในกรณีนี้ด้านในสามารถขนานกันได้ แต่มันเป็นไปไม่ได้ที่จะผ่านภาคแสดงใด ๆ ลงไป ดังนั้นงานส่วนใหญ่จะทำแบบขนาน แต่คุณกำลังสแกนทั้งตารางและการรวมบางส่วนนั้นมีราคาแพงกว่าเมื่อก่อน นี่คือแผนการที่คุณได้รับสำหรับแบบสอบถาม 2
  3. การรวมลูปทำงานแบบขนาน ด้วยลูปซ้อนกันแบบขนานเข้าร่วมด้านในของลูปรันในอนุกรม แต่คุณสามารถมีเธรด DOP ได้สูงสุดที่รันบนด้านในพร้อมกัน ชุดผลลัพธ์ภายนอกของคุณจะมีแถวเดียวดังนั้นแผนขนานของคุณจะเป็นอนุกรมได้อย่างมีประสิทธิภาพ นี่คือแผนการที่คุณจะได้รับสำหรับคิวรี 3

นี่เป็นเพียงแผนรูปทรงเดียวที่ฉันรู้ คุณสามารถหาคนอื่น ๆ ได้ถ้าคุณใช้ตารางชั่วคราว แต่ไม่มีใครแก้ปัญหาพื้นฐานของคุณได้ถ้าคุณต้องการให้ประสิทธิภาพการสืบค้นดีพอ ๆ กับแบบสอบถาม 0

คุณสามารถบรรลุประสิทธิภาพการสืบค้นเทียบเท่าโดยใช้ scalar UDF เพื่อกำหนดค่าส่งคืนให้กับตัวแปรโลคัลและใช้ตัวแปรโลคัลเหล่านั้นในเคียวรีของคุณ คุณสามารถล้อมโค้ดนั้นในโพรซีเดอร์ที่เก็บไว้หรือ UDF แบบหลายคำสั่งเพื่อหลีกเลี่ยงปัญหาการบำรุงรักษา ตัวอย่างเช่น:

DECLARE @experiment_year int = dbo.fn_GetExperimentYear(@session_id);
DECLARE @experiment_month int = dbo.fn_GetExperimentMonth(@session_id);

select
    calculated_number,
    count(*)
from dbo.f_GetSharedData(@experiment_year, @experiment_month)
group by
    calculated_number;

สเกลาร์ UDF ถูกย้ายออกไปนอกแบบสอบถามที่คุณต้องการให้มีความเท่าเทียม แผนคิวรีที่ฉันได้รับดูเหมือนจะเป็นแผนที่คุณต้องการ:

แผนแบบสอบถามแบบขนาน

ทั้งสองวิธีมีข้อเสียถ้าคุณต้องการใช้ผลลัพธ์นี้ในการสืบค้นอื่น ๆ คุณไม่สามารถเข้าร่วมกับกระบวนการจัดเก็บได้โดยตรง คุณต้องบันทึกผลลัพธ์ลงในตารางชั่วคราวที่มีปัญหาเป็นของตัวเอง คุณสามารถเข้าร่วมกับ MS-TVF แต่ใน SQL Server 2016 คุณอาจเห็นปัญหาการประมาณค่าความเป็นผู้นำ SQL Server 2017 เสนอการดำเนินการแบบอินเตอร์เลเยอร์สำหรับ MS-TVFซึ่งสามารถแก้ปัญหาได้ทั้งหมด

เพื่อเคลียร์บางสิ่ง: UDF Scalar UDFs ห้ามการขนานและ Microsoft ไม่ได้กล่าวว่า FROID จะพร้อมใช้งานใน SQL Server 2017


เกี่ยวกับ Froid ใน SQL 2017 - ไม่แน่ใจว่าทำไมฉันถึงคิดว่ามันอยู่ที่นั่น ได้รับการยืนยันให้เป็นใน vNext - brentozar.com/archive/2018/01/…
Roman Pekar

4

สิ่งนี้สามารถทำได้โดยใช้ SQLCLR ประโยชน์อย่างหนึ่งของ SQLCLR Scalar UDFs คือพวกเขาไม่ได้ป้องกันการขนานกันหากพวกเขาไม่ได้เข้าถึงข้อมูลใด ๆ (และบางครั้งก็จำเป็นต้องทำเครื่องหมายเป็น ดังนั้นคุณจะใช้ประโยชน์จากสิ่งที่ไม่ต้องการเข้าถึงข้อมูลได้อย่างไรเมื่อการดำเนินการนั้นต้องการการเข้าถึงข้อมูล

ก็เพราะdbo.Paramsตารางคาดว่าจะ:

  1. โดยทั่วไปจะไม่มีแถวมากกว่า 2,000 แถว
  2. ไม่ค่อยเปลี่ยนโครงสร้าง
  3. เฉพาะ (ปัจจุบัน) ต้องมีสองINTคอลัมน์

มันเป็นไปได้ที่จะแคชทั้งสามคอลัมน์ - session_id, experiment_year int, experiment_monthเข้าไปในคอลเล็กชั่นสแตติก (เช่นพจนานุกรมบางที) ที่มีประชากรอยู่นอกกระบวนการและอ่านโดย Scalar UDF ที่ได้รับexperiment_year intและexperiment_monthค่า สิ่งที่ฉันหมายถึงโดย "ออกกระบวนการ" คือ: คุณสามารถมี SQLCLR Scalar UDF หรือ Stored Procedure ที่แยกจากกันอย่างสมบูรณ์ซึ่งสามารถเข้าถึงการเข้าถึงข้อมูลและอ่านจากdbo.Paramsตารางเพื่อเติมข้อมูลสแตติกคอลเลกชัน UDF หรือกระบวนงานที่เก็บไว้นั้นจะถูกดำเนินการก่อนที่จะใช้ UDF ที่ได้รับค่า "ปี" และ "เดือน" วิธีการที่ UDF ที่ได้รับค่า "ปี" และ "เดือน" ไม่ได้เข้าถึงฐานข้อมูลใด ๆ

UDF หรือกระบวนงานที่เก็บไว้ที่อ่านข้อมูลสามารถตรวจสอบก่อนเพื่อดูว่าคอลเลกชันมี 0 รายการและถ้าเป็นเช่นนั้นแล้วเติมหรือข้ามไป คุณสามารถติดตามเวลาที่มีการเติมข้อมูลและหากใช้เวลาเกิน X นาที (หรืออะไรทำนองนั้น) ให้ล้างและเติมข้อมูลอีกครั้งแม้ว่าจะมีรายการในคอลเลกชันก็ตาม แต่การข้ามประชากรจะช่วยได้เนื่องจากจะต้องมีการดำเนินการบ่อยครั้งเพื่อให้แน่ใจว่าจะมีประชากรสำหรับ UDF หลักสองตัวเพื่อรับค่าจากเสมอ

ข้อกังวลหลักคือเมื่อ SQL Server ตัดสินใจที่จะยกเลิกการโหลดแอพโดเมนด้วยเหตุผลใดก็ตาม (หรือถูกทริกเกอร์โดยบางสิ่งที่ใช้DBCC FREESYSTEMCACHE('ALL');) คุณไม่ต้องการเสี่ยงว่าการล้างข้อมูลระหว่างการดำเนินการ "เติม" UDF หรือกระบวนงานที่เก็บไว้และ UDF เพื่อรับค่า "ปี" และ "เดือน" ในกรณีนี้คุณสามารถตรวจสอบจุดเริ่มต้นของ UDF ทั้งสองเพื่อโยนข้อยกเว้นหากการรวบรวมว่างเปล่าเนื่องจากเป็นการดีกว่าที่จะเกิดข้อผิดพลาดมากกว่าเพื่อให้ผลลัพธ์ที่ผิดพลาด

SAFEแน่นอนความกังวลที่กล่าวข้างต้นสันนิษฐานว่าความปรารถนาที่จะมีการประชุมทำเครื่องหมายว่าเป็น หากแอสเซมบลีสามารถทำเครื่องหมายเป็นEXTERNAL_ACCESSแล้วมันเป็นไปได้ที่จะมีการสร้างแบบคงที่ดำเนินการวิธีการอ่านข้อมูลและเติมคอลเลกชันเพื่อที่คุณจะต้องดำเนินการด้วยตนเองเพื่อรีเฟรชแถว แต่พวกเขาจะถูกบรรจุ (เนื่องจากตัวสร้างคลาสแบบสแตติกรันเสมอเมื่อโหลดคลาสซึ่งจะเกิดขึ้นเมื่อใดก็ตามที่วิธีการในคลาสนี้ถูกดำเนินการหลังจากรีสตาร์ทหรืออัปโหลดแอปโดเมน) สิ่งนี้ต้องใช้การเชื่อมต่อปกติและไม่ใช่การเชื่อมต่อบริบทในกระบวนการ (ซึ่งไม่สามารถใช้ได้กับตัวสร้างสแตติกดังนั้นจึงจำเป็นต้องใช้EXTERNAL_ACCESS)

หมายเหตุ: เพื่อที่จะไม่ต้องทำเครื่องหมายสภาเป็นUNSAFEคุณจะต้องทำเครื่องหมายใด ๆ readonlyตัวแปรระดับคงที่เป็น ซึ่งหมายความว่าอย่างน้อยที่สุดคอลเลกชัน นี่ไม่ใช่ปัญหาเนื่องจากคอลเลกชันแบบอ่านอย่างเดียวสามารถมีรายการที่เพิ่มหรือลบออกจากพวกเขาพวกเขาก็ไม่สามารถเริ่มต้นนอก Constructor หรือโหลดเริ่มต้น การติดตามเวลาที่โหลดคอลเลกชันเพื่อจุดประสงค์ในการหมดอายุหลังจาก X นาทีนั้นยากกว่าเนื่องจากstatic readonly DateTimeตัวแปรคลาสไม่สามารถเปลี่ยนแปลงได้นอกตัวสร้างหรือโหลดเริ่มต้น หากต้องการหลีกเลี่ยงข้อ จำกัด นี้คุณต้องใช้คอลเลกชันแบบคงที่อ่านอย่างเดียวที่มีรายการเดียวที่เป็นDateTimeค่าเพื่อให้สามารถลบออกและเพิ่มใหม่อีกครั้งเมื่อรีเฟรช


ไม่ทราบว่าทำไมมีคนลงคะแนนนี้ แม้ว่าจะไม่ใช่แบบทั่วไปฉันคิดว่ามันสามารถใช้งานได้ในกรณีปัจจุบันของฉัน ฉันต้องการมีโซลูชัน SQL ที่บริสุทธิ์ แต่ฉันจะตรวจสอบอย่างละเอียดและลองดูว่าใช้ได้หรือไม่
Roman Pekar

@ RomanPekar ไม่แน่ใจ แต่มีคนมากมายที่นั่นต่อต้าน SQLCLR และอาจมีบางอย่างที่ต่อต้านฉัน ;-) ไม่ว่าจะด้วยวิธีใดฉันไม่สามารถคิดได้ว่าทำไมโซลูชันนี้จึงใช้งานไม่ได้ ฉันเข้าใจความต้องการของ T-SQL อย่างแท้จริง แต่ฉันไม่รู้วิธีที่จะทำให้เกิดขึ้นและถ้าไม่มีคำตอบที่แข่งขันอาจไม่มีใครทำเช่นนั้น ฉันไม่รู้ว่าตารางเพิ่มประสิทธิภาพหน่วยความจำและ UDF ที่คอมไพล์แล้วจะทำอะไรได้ดีกว่าที่นี่ นอกจากนี้ฉันเพิ่งเพิ่มย่อหน้าที่มีหมายเหตุการใช้งานบางอย่างเพื่อให้ทราบ
โซโลมอน Rutzky

1
ฉันไม่เคยมั่นใจอย่างเต็มที่ว่าการใช้readonly staticsนั้นปลอดภัยหรือฉลาดใน SQLCLR ฉันเชื่อมั่นมากขึ้นแล้วว่าจะหลอกระบบโดยการสร้างreadonlyประเภทการอ้างอิงซึ่งคุณจะเปลี่ยนไป ให้ความรู้สึกที่แท้จริงแก่ฉัน
พอลไวท์ 9

@ PaulWhite เข้าใจดีและฉันจำได้ว่าเรื่องนี้เกิดขึ้นในการสนทนาส่วนตัวเมื่อหลายปีก่อน เมื่อพิจารณาถึงลักษณะที่ใช้ร่วมกันของ App Domains (และstaticวัตถุอื่น ๆ ) ใน SQL Server ใช่มีความเสี่ยงต่อสภาพการแข่งขัน นั่นคือเหตุผลที่ฉันตัดสินใจครั้งแรกจาก OP ว่าข้อมูลนี้มีน้อยและมีเสถียรภาพและทำไมฉันถึงต้องใช้วิธีนี้ในการกำหนดว่า "ไม่ค่อยเปลี่ยนแปลง" และให้วิธีการรีเฟรชเมื่อต้องการ ในนี้กรณีการใช้งานฉันไม่เห็นมากถ้าความเสี่ยงใด ๆ ฉันพบโพสต์เมื่อหลายปีก่อนเกี่ยวกับความสามารถในการอัปเดตคอลเลกชันแบบอ่านอย่างเดียวโดยการออกแบบ (ใน C #, ไม่มีการอภิปรายอีกครั้ง: SQLCLR) จะพยายามหามัน
โซโลมอน Rutzky

2
ไม่จำเป็นไม่มีทางที่คุณจะทำให้ฉันคุ้นเคยกับเอกสารฉบับนี้นอกเหนือจาก SQL Server อย่างเป็นทางการว่ามันใช้ได้ดีซึ่งฉันค่อนข้างมั่นใจว่าไม่มีอยู่จริง
พอลไวท์ 9
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.