متى يجب استخدام عبر تطبيق على الداخلية الانضمام ؟
-
16-09-2019 - |
سؤال
ما هو الغرض الرئيسي من استخدام عبر تطبيق?
لقد قرأت (غامضة ، من خلال وظيفة على الإنترنت) cross apply
يمكن أن يكون أكثر كفاءة عند اختيار أكثر من مجموعات البيانات الكبيرة إذا كنت التقسيم.(الترحيل) ،
وأنا أعلم أيضا أن CROSS APPLY
لا تتطلب UDF كما الحق-الجدول.
في معظم INNER JOIN
استفسارات (واحد إلى كثير من العلاقات), لا يمكن إعادة كتابة لهم استخدام CROSS APPLY
, لكنهم دائما تعطيني ما يعادل تنفيذ الخطط.
يمكن لأي شخص أن تعطيني مثال جيد عندما CROSS APPLY
فرقا في تلك الحالات التي يكون فيها INNER JOIN
سوف تعمل أيضا ؟
تحرير:
وهنا تافهة سبيل المثال ، حيث تنفيذ الخطط هي بالضبط نفس.(تظهر لي واحد حيث أنها تختلف من حيث cross apply
هو أسرع/أكثر كفاءة)
create table Company (
companyId int identity(1,1)
, companyName varchar(100)
, zipcode varchar(10)
, constraint PK_Company primary key (companyId)
)
GO
create table Person (
personId int identity(1,1)
, personName varchar(100)
, companyId int
, constraint FK_Person_CompanyId foreign key (companyId) references dbo.Company(companyId)
, constraint PK_Person primary key (personId)
)
GO
insert Company
select 'ABC Company', '19808' union
select 'XYZ Company', '08534' union
select '123 Company', '10016'
insert Person
select 'Alan', 1 union
select 'Bobby', 1 union
select 'Chris', 1 union
select 'Xavier', 2 union
select 'Yoshi', 2 union
select 'Zambrano', 2 union
select 'Player 1', 3 union
select 'Player 2', 3 union
select 'Player 3', 3
/* using CROSS APPLY */
select *
from Person p
cross apply (
select *
from Company c
where p.companyid = c.companyId
) Czip
/* the equivalent query using INNER JOIN */
select *
from Person p
inner join Company c on p.companyid = c.companyId
المحلول
هل يمكن لأي شخص أن يعطيني مثالا جيدا عند تطبيق الصليب تحدث فرقا في هذه الحالات التي ستعمل فيها الانضمام الداخلي أيضا؟
انظر المقال في مدونتي لمقارنة أداء مفصلة:
CROSS APPLY
يعمل بشكل أفضل على الأشياء التي ليس لها بسيطة JOIN
شرط.
يختار هذا واحد 3
السجلات الأخيرة من t2
لكل سجل من t1
:
SELECT t1.*, t2o.*
FROM t1
CROSS APPLY
(
SELECT TOP 3 *
FROM t2
WHERE t2.t1_id = t1.id
ORDER BY
t2.rank DESC
) t2o
لا يمكن صياغته بسهولة مع INNER JOIN
شرط.
ربما يمكنك القيام بشيء من هذا القبيل باستخدام CTE
وظيفة ونافذة وظيفة:
WITH t2o AS
(
SELECT t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn
FROM t2
)
SELECT t1.*, t2o.*
FROM t1
INNER JOIN
t2o
ON t2o.t1_id = t1.id
AND t2o.rn <= 3
, ، ولكن هذا أقل قابلية للقراءة وربما أقل كفاءة.
تحديث:
فقط التحقق.
master
هو جدول حول 20,000,000
سجلات مع أ PRIMARY KEY
على id
.
هذا الاستعلام:
WITH q AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM master
),
t AS
(
SELECT 1 AS id
UNION ALL
SELECT 2
)
SELECT *
FROM t
JOIN q
ON q.rn <= t.id
يعمل تقريبا 30
ثواني، في حين أن هذا واحد:
WITH t AS
(
SELECT 1 AS id
UNION ALL
SELECT 2
)
SELECT *
FROM t
CROSS APPLY
(
SELECT TOP (t.id) m.*
FROM master m
ORDER BY
id
) q
هو لحظة.
نصائح أخرى
cross apply
يمكنك في بعض الأحيان من القيام بأشياء لا يمكنك القيام بها inner join
.
مثال (خطأ في بناء الجملة):
select F.* from sys.objects O
inner join dbo.myTableFun(O.name) F
on F.schema_id= O.schema_id
هذا ال خطأ في بناء الجملة, ، لأنه عند استخدامها مع inner join
, وظائف الجدول يمكن أن تأخذ فقط المتغيرات أو الثوابت كما المعلمات. (أي لا يمكن أن تعتمد المعلمة وظيفة الجدول على عمود جدول آخر.)
ومع ذلك:
select F.* from sys.objects O
cross apply ( select * from dbo.myTableFun(O.name) ) F
where F.schema_id= O.schema_id
هذا قانونية.
يحرر:أو بدلا من ذلك، بناء جملة أقصر: (عن طريق إيق
select F.* from sys.objects O
cross apply dbo.myTableFun(O.name) F
where F.schema_id= O.schema_id
يحرر:
ملاحظة: Informix 12.10 XC2 + لديه الجداول المشتقة الجانبي و postgresql (9.3+) لديه السدود الجانبية والتي يمكن استخدامها تأثير مماثل.
النظر في أن لديك طاولتين.
الجدول الرئيسي
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
تفاصيل طاولة
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
هناك العديد من المواقف التي نحتاج فيها إلى استبدالها INNER JOIN
مع CROSS APPLY
.
1. انضم إلى طاولتين بناء على TOP n
النتائج
النظر في ما إذا كنا بحاجة إلى الاختيار Id
و Name
من Master
وآخر تواريخ لكل منهما Id
من Details table
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
الاستعلام أعلاه يولد النتيجة التالية.
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
x------x---------x--------------x-------x
انظر، لقد ولدت نتائج لآخر تواريخ تواريخ مع آخر تاريخين Id
ثم انضم إلى هذه السجلات فقط في الاستعلام الخارجي Id
, ، وهذا خطأ. لإنجاز هذا، نحتاج إلى استخدام CROSS APPLY
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ويشكل النتيجة التالية.
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
x------x---------x--------------x-------x
وإليك كيف يعمل. الاستعلام في الداخل CROSS APPLY
يمكن الرجوع إلى الجدول الخارجي، حيث INNER JOIN
لا يمكن القيام بذلك (يرمي خطأ في الترجمة). عند العثور على آخر تواريخ، يتم الانضمام في الداخل CROSS APPLY
بمعنى آخر، WHERE M.ID=D.ID
.
2. عندما نحتاج INNER JOIN
وظيفة باستخدام الوظائف.
CROSS APPLY
يمكن استخدامها كبديل مع INNER JOIN
عندما نحتاج إلى الحصول على نتيجة من Master
الجدول و function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
وهنا وظيفة
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
الذي ولدت النتيجة التالية
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
x------x---------x--------------x-------x
ميزة إضافية من التقاطع
APPLY
يمكن استخدامها كبديل ل UNPIVOT
. وبعد إما CROSS APPLY
أو OUTER APPLY
يمكن استخدامها هنا، والتي تقابلها.
فكر في أن لديك الجدول أدناه (اسمه MYTABLE
).
x------x-------------x--------------x
| Id | FROMDATE | TODATE |
x------x-------------x--------------x
| 1 | 2014-01-11 | 2014-01-13 |
| 1 | 2014-02-23 | 2014-02-27 |
| 2 | 2014-05-06 | 2014-05-30 |
| 3 | NULL | NULL |
x------x-------------x--------------x
الاستعلام أدناه.
SELECT DISTINCT ID,DATES
FROM MYTABLE
CROSS APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
الذي يجلب لك النتيجة
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
| 3 | NULL |
x------x-------------x
يبدو لي أن عبر تطبيق يمكن ملء فجوة معينة عند العمل مع الحقول المحسوبة في مجمع/المتداخلة الاستعلامات, وجعلها أكثر بساطة و أكثر قابلية للقراءة.
مثال بسيط:لديك دوب و تريد تقديم متعددة سن المجالات ذات الصلة التي سوف تعتمد أيضا على مصادر البيانات الأخرى (مثل العمالة) ، مثل العمر ، AgeGroup, AgeAtHiring, MinimumRetirementDate ، إلخ.للاستخدام في التطبيقات للمستخدم النهائي (Excel PivotTables ، على سبيل المثال).
الخيارات محدودة و نادرا أنيقة:
الانضمام إلى الاستعلامات الفرعية لا يمكن إدخال قيم جديدة في مجموعة البيانات استنادا إلى البيانات في الأصل الاستعلام (يجب أن تقف على قدميها).
UDFs أنيق ، ولكن بطيئة كما أنها تميل إلى منع عمليات موازية.ويجري كيان منفصل يمكن أن تكون جيدة (رمز أقل) أو سيئة (حيث هو رمز) الشيء.
تقاطع الجداول.في بعض الأحيان أنها يمكن أن تعمل ، ولكن قريبا بما فيه الكفاية أنت الانضمام الاستعلامات الفرعية مع طن من النقابات.فوضى كبيرة.
خلق آخر واحد الغرض الرأي ، على افتراض الحسابات الخاصة بك لا تحتاج إلى البيانات التي تم الحصول عليها في منتصف الطريق من خلال الرئيسي الخاص بك الاستعلام.
الوسيط الجداول.نعم...التي عادة ما يعمل ، وغالبا ما تكون خيارا جيدا لأنها يمكن فهرستها و سريع لكن الأداء أيضا إسقاط بسبب تحديث البيانات لا يجري بالتوازي وعدم السماح تتالي الصيغ (إعادة استخدام النتائج) لتحديث العديد من المجالات داخل نفس البيان.وأحيانا كنت تفضل أن تفعل أشياء في مرور واحد.
التعشيش الاستعلامات.نعم في أي وقت يمكنك وضع أقواس على كامل الاستعلام واستخدامه بمثابة فرعي التي يمكنك التعامل مع مصدر البيانات والحقول المحسوبة على حد سواء.ولكن يمكنك فقط القيام بذلك كثيرا قبل أن يحصل على القبيح.قبيحة جدا.
تكرار التعليمات البرمجية.ما هو أعظم قيمة من 3 طويلة (القضية...آخر...END) التصريحات ؟ التي سوف تكون قابلة للقراءة!
- أخبر العملاء لحساب الأشياء نفسها.
هل فاتني شيء ؟ ربما لذلك لا تتردد في التعليق.ولكن مهلا ، عبر تطبيق مثل هبة من السماء في مثل هذه الحالات:يمكنك فقط إضافة بسيطة CROSS APPLY (select tbl.value + 1 as someFormula) as crossTbl
وفويلا!الجديد الخاص بك المجال هي الآن جاهزة للاستخدام عمليا مثل أنه كان دائما هناك في البيانات المصدر.
القيم التي أدخلت عبر تطبيق يمكن...
- يمكن استخدامها لإنشاء واحد أو أكثر من الحقول المحسوبة دون إضافة الأداء تعقيد أو القراءة القضايا إلى المزيج
- مثل ينضم عدة اللاحقة عبر تطبيق بيانات يمكن الرجوع إلى أنفسهم:
CROSS APPLY (select crossTbl.someFormula + 1 as someMoreFormula) as crossTbl2
- يمكنك استخدام القيم التي أدخلتها عبر تطبيق اللاحقة شروط الانضمام
- علاوة على ذلك هناك قيم الجدول وظيفة الجانب
اللعنة, لا يوجد شيء أنها لا يمكن أن تفعل!
عبر تطبيق يعمل بشكل جيد مع حقل XML أيضا. إذا كنت ترغب في تحديد قيم العقدة في تركيبة مع الحقول الأخرى.
على سبيل المثال، إذا كان لديك جدول يحتوي على بعض XML
<root> <subnode1> <some_node value="1" /> <some_node value="2" /> <some_node value="3" /> <some_node value="4" /> </subnode1> </root>
باستخدام الاستعلام
SELECT
id as [xt_id]
,xmlfield.value('(/root/@attribute)[1]', 'varchar(50)') root_attribute_value
,node_attribute_value = [some_node].value('@value', 'int')
,lt.lt_name
FROM dbo.table_with_xml xt
CROSS APPLY xmlfield.nodes('/root/subnode1/some_node') as g ([some_node])
LEFT OUTER JOIN dbo.lookup_table lt
ON [some_node].value('@value', 'int') = lt.lt_id
سوف تعيد النتيجة
xt_id root_attribute_value node_attribute_value lt_name
----------------------------------------------------------------------
1 test1 1 Benefits
1 test1 4 FINRPTCOMPANY
تم الرد على هذا بالفعل بشكل جيد للغاية من الناحية الفنية، لكن اسمحوا لي أن أعطي مثالا ملموسا حول كيفية مفيد للغاية:
دعنا نقول أن لديك اثنين من الجداول والعميل والنظام. العملاء لديهم العديد من الطلبات.
أريد أن أخلق وجهة نظر تعطيني تفاصيل حول العملاء، وأحدث طلبين لديهم. مع انضمام فقط، هذا سيتطلب بعض الانضمام الذاتي والتجميع الذي ليس جميلا. ولكن مع التقليب تطبيق، سهل للغاية:
SELECT *
FROM Customer
CROSS APPLY (
SELECT TOP 1 *
FROM Order
WHERE Order.CustomerId = Customer.CustomerId
ORDER BY OrderDate DESC
) T
يمكن استخدام Cross Supply لتحل محل Squarquery حيث تحتاج إلى عمود من الاسمية الاسمية
Suacquery.
select * from person p where
p.companyId in(select c.companyId from company c where c.companyname like '%yyy%')
هنا لن أكون قادرا على تحديد أعمدة جدول الشركة، مما باستخدام تطبيق متقاطع
select P.*,T.CompanyName
from Person p
cross apply (
select *
from Company C
where p.companyid = c.companyId and c.CompanyName like '%yyy%'
) T
أعتقد أنه يجب أن تكون سريدا؛)
SPRICE STUP سيكون فريدا إلى حد ما بالنسبة للأشخاص الذين يقرؤون أن يخبرهم أن UDF يستخدم سيتم تطبيقه على كل صف من الجدول على اليسار.
فكورسي، هناك قيود أخرى حيث يتم استخدام التقاطع أفضل من الانضمام الذي أرسله الأصدقاء الآخرون أعلاه.
فيما يلي مقال يشرح كل شيء، مع اختلاف أدائه واستخدامه على الانضمام.
SQL Server Cross تطبيق وتطبيق الخارجي
كما هو مقترح في هذه المقالة، لا يوجد فرق أداء بينها من أجل عمليات الانضمام العادية (الداخلية والعبر).
يصل فرق الاستخدام عندما تضطر إلى القيام باستعلام مثل هذا:
CREATE FUNCTION dbo.fn_GetAllEmployeeOfADepartment(@DeptID AS INT)
RETURNS TABLE
AS
RETURN
(
SELECT * FROM Employee E
WHERE E.DepartmentID = @DeptID
)
GO
SELECT * FROM Department D
CROSS APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)
وهذا هو، عندما تضطر إلى الارتباط مع وظيفة. لا يمكن القيام بذلك باستخدام الانضمام الداخلي، والتي من شأنها أن تعطيك الخطأ "المعرف متعدد الأجزاء" لا يمكن ربطه ". هنا يتم تمرير القيمة إلى الوظيفة حيث يتم قراءة كل صف. يبدو رائع لي. :)
حسنا، لست متأكدا مما إذا كان هذا مؤهلا كسبب لاستخدامه عبر التطبيق مقابل الانضمام مقابل الانضمام مقابل ذلك، ولكن تمت الرد على هذا الاستعلام لي في منشور المنتدى باستخدام Cross Supply، لذلك لست متأكدا مما إذا كان هناك طريقة تعاليل باستخدام Inner Join:
Create PROCEDURE [dbo].[Message_FindHighestMatches]
-- Declare the Topical Neighborhood
@TopicalNeighborhood nchar(255)
كما تبدأ
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
Create table #temp
(
MessageID int,
Subjects nchar(255),
SubjectsCount int
)
Insert into #temp Select MessageID, Subjects, SubjectsCount From Message
Select Top 20 MessageID, Subjects, SubjectsCount,
(t.cnt * 100)/t3.inputvalues as MatchPercentage
From #temp
cross apply (select count(*) as cnt from dbo.Split(Subjects,',') as t1
join dbo.Split(@TopicalNeighborhood,',') as t2
on t1.value = t2.value) as t
cross apply (select count(*) as inputValues from dbo.Split(@TopicalNeighborhood,',')) as t3
Order By MatchPercentage desc
drop table #temp
نهاية
جوهر تشغيل المشغل هو السماح بالارتباط بين الجانب الأيسر والأيمن من المشغل في جملة من البند.
على عكس الانضمام، لا يسمح بالارتباط بين المدخلات.
تحدث عن الارتباط في تطبيق المشغل، أقصد على الجانب الأيمن الذي يمكننا وضعه:
- جدول مشتق - كعقود استقبال مرتبط مع اسم مستعار
- وظيفة قيمة الجدول - عرض مفاهيمي مع المعلمات، حيث يمكن للمعلمة الرجوع إلى الجانب الأيسر
كلاهما يمكن أن يرجع أعمدة متعددة والصفوف.
ربما يكون هذا سؤالا قديما، لكن ما زلت أحب قوة الصليب تنطبق على تبسيط إعادة استخدام المنطق وتوفير آلية "تسلسل" للنتائج.
لقد قدمت كمان SQL أدناه والتي تظهر مثالا بسيطا على كيفية استخدام Cross Supply لإجراء عمليات منطقية معقدة على مجموعة البيانات الخاصة بك دون أن تحصل على أشياء فوضوي. ليس من الصعب استقراء من هنا حسابات أكثر تعقيدا.