هل هناك خطأ في الصلات التي لا تستخدم الكلمة الأساسية JOIN في SQL أو MySQL؟

StackOverflow https://stackoverflow.com/questions/128965

  •  02-07-2019
  •  | 
  •  

سؤال

عندما بدأت في كتابة استعلامات قاعدة البيانات، لم أكن أعرف الكلمة الأساسية JOIN بعد، وبطبيعة الحال قمت بتوسيع ما أعرفه بالفعل وكتبت استعلامات مثل هذا:

SELECT a.someRow, b.someRow 
FROM tableA AS a, tableB AS b 
WHERE a.ID=b.ID AND b.ID= $someVar

الآن بعد أن علمت أن هذا هو نفس INNER JOIN، أجد كل هذه الاستعلامات في الكود الخاص بي وأسأل نفسي إذا كان يجب علي إعادة كتابتها.هل هناك شيء كريه الرائحة فيهم أم أنهم بخير؟


يحرر:

ملخص إجابتي:لا حرج في هذا الاستعلام ولكن استخدام الكلمات الرئيسية سيؤدي على الأرجح إلى جعل الكود أكثر قابلية للقراءة/الصيانة.

استنتاجي:لن أغير استفساراتي القديمة ولكني سأصحح أسلوب كتابتي وأستخدم الكلمات الرئيسية في المستقبل.

شكرا لإجاباتك!

هل كانت مفيدة؟

المحلول

تصفية الانضمام فقط باستخدام WHERE يمكن أن تكون غير فعالة للغاية في بعض السيناريوهات الشائعة.على سبيل المثال:

SELECT * FROM people p, companies c 
    WHERE p.companyID = c.id AND p.firstName = 'Daniel'

ستنفذ معظم قواعد البيانات هذا الاستعلام بشكل حرفي تمامًا، حيث تأخذ أولاً الأمر المنتج الديكارتي التابع people و companies الجداول و ثم التصفية حسب تلك التي لديها مطابقة companyID و id مجالات.في حين أن المنتج غير المقيد بالكامل لا يوجد في أي مكان إلا في الذاكرة، ثم للحظة واحدة فقط، فإن حسابه يستغرق بعض الوقت.

النهج الأفضل هو تجميع القيود مع JOINعند الاقتضاء.هذا ليس فقط أسهل في القراءة بشكل شخصي ولكنه أيضًا أكثر كفاءة.وبالتالي:

SELECT * FROM people p JOIN companies c ON p.companyID = c.id
    WHERE p.firstName = 'Daniel'

إنها أطول قليلاً، لكن قاعدة البيانات قادرة على إلقاء نظرة على ملف ON جملة واستخدامها لحساب المقيدة بالكامل JOIN مباشرة، بدلاً من البدء بها كل شئ ومن ثم الحد إلى أسفل.يعد هذا أسرع في الحساب (خاصة مع مجموعات البيانات الكبيرة و/أو صلات الجداول المتعددة) ويتطلب ذاكرة أقل.

أقوم بتغيير كل استعلام أراه والذي يستخدم "comma JOIN" بناء الجملة.في رأيي، الغرض الوحيد من وجودها هو الإيجاز.وبالنظر إلى تأثير الأداء، لا أعتقد أن هذا سبب مقنع.

نصائح أخرى

كلما كان أكثر مطولا INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN من بناء جملة ANSI SQL/92 للانضمام.بالنسبة لي، هذا الإسهاب يجعل الانضمام أكثر وضوحًا للمطور/DBA حول الهدف من الانضمام.

في SQL Server، توجد دائمًا خطط استعلام للتحقق منها، ويمكن إجراء إخراج نص على النحو التالي:

SET SHOWPLAN_ALL ON
GO

DECLARE @TABLE_A TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_A
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

DECLARE @TABLE_B TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_B
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A, @TABLE_B AS B
WHERE
    A.ID = B.ID

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A
    INNER JOIN @TABLE_B AS B ON A.ID = B.ID

سأحذف الآن خطة إنشاء متغير الجدول، لكن الخطة لكلا الاستعلامين متطابقة:

 SELECT A.Data, B.Data  FROM   @TABLE_A AS A, @TABLE_B AS B  WHERE   A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)
 SELECT A.Data, B.Data  FROM   @TABLE_A AS A   INNER JOIN @TABLE_B AS B ON A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)

لذا، إجابة مختصرة - لا داعي لإعادة الكتابة، إلا إذا كنت تقضي وقتًا طويلاً في محاولة قراءتها في كل مرة تقوم فيها بصيانتها؟

إنه أكثر من مجرد اختيار بناء الجملة.أفضل تجميع شروط الانضمام الخاصة بي مع الصلات الخاصة بي، ومن ثم أستخدم بناء جملة INNER JOIN

SELECT a.someRow, b.someRow
FROM tableA AS a
INNER JOIN tableB AS b
  ON a.ID = b.ID
WHERE b.ID = ?

(؟كونه عنصرًا نائبًا)

ليس هناك خطأ في بناء الجملة في المثال الخاص بك.يُطلق على بناء جملة "INNER JOIN" عمومًا اسم بناء جملة "ANSI"، ويأتي بعد النمط الموضح في المثال الخاص بك.إنه موجود لتوضيح نوع/اتجاه/مكونات الصلة، ولكنه لا يختلف وظيفيًا بشكل عام عما لديك.

يعد دعم عمليات الانضمام "ANSI" بمثابة نظام أساسي لكل قاعدة بيانات، ولكنه أصبح عالميًا إلى حد ما هذه الأيام.

كملاحظة جانبية، إحدى الإضافات التي تحتوي على بناء الجملة "ANSI" كانت "FULL OUTER JOIN" أو "FULL JOIN".

أتمنى أن يساعدك هذا.

على العموم:

استخدم الكلمة الأساسية JOIN للربط (على سبيل المثال."الانضمام") المفاتيح الأساسية والمفاتيح الخارجية.

استخدم جملة WHERE لقصر مجموعة النتائج الخاصة بك على السجلات التي تهمك فقط.

المشكلة الوحيدة التي يمكن أن تنشأ هي عند محاولة مزج صلة "نمط الفاصلة" القديمة مع صلات SQL-92 في نفس الاستعلام، على سبيل المثال، إذا كنت بحاجة إلى صلة داخلية واحدة وعلاقة خارجية أخرى.

SELECT *
FROM table1 AS a, table2 AS b
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1
WHERE a.column2 = b.column2;

المشكلة هي أن معايير SQL الحديثة تقول أنه يتم تقييم JOIN قبل الصلة بالفاصلة.لذا فإن الإشارة إلى "a" في عبارة ON تعطي خطأً، لأنه لم يتم تعريف اسم الارتباط بعد حيث يتم تقييم عبارة ON هذه.هذا خطأ مربك للغاية.

الحل هو عدم الخلط بين نمطي الصلات.يمكنك الاستمرار في استخدام نمط الفاصلة في التعليمات البرمجية القديمة، ولكن إذا كتبت استعلامًا جديدًا، فقم بتحويل كافة الصلات إلى نمط SQL-92.

SELECT *
FROM table1 AS a
 INNER JOIN table2 AS b ON a.column2 = b.column2
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1;

شيء آخر يجب مراعاته في بناء جملة الانضمام القديم هو أنه من السهل جدًا الحصول على ربط مفصل عن طريق الصدفة نظرًا لعدم وجود بند.إذا كانت الكلمة الأساسية المميزة موجودة في الاستعلام وتستخدم صلات النمط القديم، فقم بتحويلها إلى صلة قياسية ANSI ومعرفة ما إذا كنت لا تزال بحاجة إلى وصلة النمط المميزة.إذا كنت تقوم بإصلاح عمليات الربط غير المقصودة بهذه الطريقة، فيمكنك تحسين الأداء بشكل كبير عن طريق إعادة الكتابة لتحديد الربط وحقول الربط.

أتجنب الصلات الضمنية؛عندما يكون الاستعلام كبيرًا جدًا، فإنه يجعل من الصعب فك الشفرة

مع الصلات الواضحة والتنسيق الجيد، تكون التعليمات البرمجية أكثر قابلية للقراءة والفهم دون الحاجة إلى التعليقات.

يعتمد ذلك أيضًا على ما إذا كنت تقوم فقط بالصلات الداخلية بهذه الطريقة أو الروابط الخارجية أيضًا.على سبيل المثال، يمكن أن يعطي بناء جملة MS SQL Server للصلات الخارجية في جملة WHERE (=* و*=) نتائج مختلفة عن بناء جملة OUTER JOIN ولم يعد مدعومًا (http://msdn.microsoft.com/en-us/library/ms178653(SQL.90).aspx) في SQL Server 2005.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top