تحسين استعلام MySQL مع جملة كبيرة في () أو انضم إلى جدول مشتق
-
21-09-2019 - |
سؤال
دعنا نقول أنني بحاجة إلى الاستعلام عن شركاء الشركة. لدي جدول ، "المعاملات" ، التي تحتوي على بيانات عن كل معاملة تم إجراؤها.
CREATE TABLE `transactions` (
`transactionID` int(11) unsigned NOT NULL,
`orderID` int(11) unsigned NOT NULL,
`customerID` int(11) unsigned NOT NULL,
`employeeID` int(11) unsigned NOT NULL,
`corporationID` int(11) unsigned NOT NULL,
PRIMARY KEY (`transactionID`),
KEY `orderID` (`orderID`),
KEY `customerID` (`customerID`),
KEY `employeeID` (`employeeID`),
KEY `corporationID` (`corporationID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
من السهل إلى حد ما الاستعلام عن هذا الجدول للمنتسبين ، ولكن هناك تطور: يتم تسجيل سجل المعاملات مرة واحدة لكل موظف ، وبالتالي قد يكون هناك سجلات متعددة لشركة واحدة لكل طلب.
على سبيل المثال ، إذا كان الموظفون A و B من Corporation 1 يشاركان في بيع مكنسة كهربائية للشركة 2 ، فسيكون هناك سجلان في جدول "المعاملات" ؛ واحد لكل موظف ، وكلاهما للشركة 1. يجب ألا يؤثر هذا على النتائج. يجب معاملة التجارة من الشركة 1 ، بغض النظر عن عدد موظفيها ، على أنها واحدة.
من السهل ، اعتقدت. سأقوم فقط بالانضمام إلى طاولة مشتقة ، مثل ذلك:
SELECT corporationID FROM transactions JOIN (SELECT DISTINCT orderID FROM transactions WHERE corporationID = 1) AS foo USING (orderID)
يعيد الاستعلام قائمة الشركات التي شاركت في التداولات مع الشركة 1. هذا بالضبط ما أحتاجه ، لكنه بطيء للغاية لأن MySQL لا يمكنه استخدام مؤشر CorporationId لتحديد الجدول المشتق. أفهم أن هذا هو الحال بالنسبة لجميع الجداول الفرعية/المشتقة في MySQL.
لقد حاولت أيضًا الاستعلام عن مجموعة من OrderIDs بشكل منفصل واستخدام جملة كبيرة بشكل يبعث على السخرية () (Typhically 100 000+ ids) ، ولكن كما اتضح أن MySQL لديه مشاكل تستخدم مؤشرات على شروط كبيرة يبعث على السخرية () ونتيجة لا تتحسن وقت الاستعلام.
هل هناك أي خيارات أخرى متاحة ، أم قمت بالإرهاق كل منهما؟
المحلول
إذا فهمت متطلباتك ، فيمكنك تجربة ذلك.
select distinct t1.corporationID
from transactions t1
where exists (
select 1
from transactions t2
where t2.corporationID = 1
and t2.orderID = t1.orderID)
and t1.corporationID != 1;
أو هذا:
select distinct t1.corporationID
from transactions t1
join transactions t2
on t2.orderID = t1.orderID
and t1.transactionID != t2.transactionID
where t2.corporationID = 1
and t1.corporationID != 1;
نصائح أخرى
لا معنى لها لبياناتك ، أعتقد أنك تستخدم CorporationId حيث تعني معرف العميل في مرحلة ما هناك ، حيث ينضم استعلامك إلى جدول المعاملات إلى جدول المعاملات لـ CorporationId = 1 استنادًا إلى OrderID للحصول على الشركات ... أيهما سيكون 1 ، أليس كذلك؟
هل يمكنك تحديد ما يعنيه العميل ، الموظف ، و CorporationIDs؟ كيف أعرف أن الموظفين A و B هم من Corporation 1 - في هذه الحالة ، هل الشركة 1 هي CorporationId ، و Corporation 2 هي العميل ، وهي مخزنة في العميل؟
إذا كان هذا هو الحال ، فأنت بحاجة فقط إلى القيام بمجموعة:
SELECT customerID
FROM transactions
WHERE corporationID = 1
GROUP BY customerID
(أو حدد وتجمع من OrderId إذا كنت تريد صفًا واحدًا لكل طلب بدلاً من صف واحد لكل عميل.)
باستخدام المجموعة ، فأنت تتجاهل حقيقة أن هناك سجلات متعددة مكررة باستثناء الموظف.
على العكس ، لإرجاع جميع الشركات التي بيعت إلى الشركة 2.
SELECT corporationID
FROM transactions
WHERE customerID = 2
GROUP BY corporationID