سؤال

لقد تعلمت شيئًا بسيطًا عن SQL في اليوم الآخر:

SELECT c FROM myTbl GROUP BY C

له نفس النتيجة مثل:

SELECT DISTINCT C FROM myTbl

ما يثير فضولي هو هل هناك أي شيء مختلف في الطريقة التي يعالج بها محرك SQL الأمر، أم أنهما نفس الشيء حقًا؟

أنا شخصيا أفضل بناء الجملة المتميز، ولكنني متأكد من أنه خارج نطاق العادة أكثر من أي شيء آخر.

يحرر:هذا ليس سؤالاً عن المجاميع.استخدام GROUP BY مع وظائف التجميعية مفهومة.

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

المحلول

MusiGenesis "الاستجابة وظيفيا واحدة صحيحة فيما يتعلق سؤالك كما ورد. في SQL Server غير ذكي بما فيه الكفاية لندرك أنه إذا كنت تستخدم "المجموعة حسب" وعدم استخدام أية وظائف الكلي، ثم ما تعنيه فعلا هو "متميزة" - وبالتالي فإنه يقوم بإنشاء خطة التنفيذ كما لو كنت تستخدم ببساطة "متميزة . "

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

ومطرقة يمكن أن تعمل القيادة في المسمار في بعض الأحيان، ولكن إذا كنت قد حصلت على مفك البراغي مفيد، لماذا؟

و(لأغراض هذا التشبيه، Hammer : Screwdriver :: GroupBy : Distinct وscrew => get list of unique values in a table column)

نصائح أخرى

وGROUP BY يتيح لك استخدام دالات التجميع، مثل AVG، MAX، MIN، SUM، وCOUNT. على DISTINCT ناحية أخرى فقط يزيل مكررة.

وعلى سبيل المثال، إذا كان لديك مجموعة من سجلات الشراء، وتريد أن تعرف كم أنفق من قبل كل قسم، قد تفعل شيئا مثل:

SELECT department, SUM(amount) FROM purchases GROUP BY department

وهذا سوف تعطيك صف واحد لكل قسم، التي تحتوي على اسم القسم ومجموع كل القيم amount في كافة الصفوف لهذا القسم.

ليس هناك فرق (في SQL Server، على الأقل).يستخدم كلا الاستعلامين نفس خطة التنفيذ.

http://sqlmag.com/database-performance-tuning/distinct-vs-group

ربما هناك يكون فرق، إذا كانت هناك استعلامات فرعية معنية:

http://blog.sqlauthority.com/2007/03/29/sql-server-difference-between-distinct-and-group-by-distinct-vs-group-by/

ليس هناك فرق (أسلوب أوراكل):

http://asktom.Oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212

استخدم DISTINCT إذا كنت ترغب فقط في إزالة التكرارات. استخدام GROUPY BY إذا كنت تريد تطبيق مشغلي الإجمالية (MAX، SUM، GROUP_CONCAT، ...، أو شرط HAVING).

ما هو الفرق من مجرد وجهة نظر وظيفة إزالة مكررة

وبصرف النظر عن حقيقة أنه على عكس DISTINCT, GROUP BY يسمح بتجميع البيانات لكل مجموعة (والذي تم ذكره في العديد من الإجابات الأخرى)، والفرق الأكثر أهمية في رأيي هو حقيقة أن العمليتين "تحدثان" في خطوتين مختلفتين للغاية في الترتيب المنطقي للعمليات التي يتم تنفيذها في SELECT إفادة.

وإليكم أهم العمليات:

  • FROM (مشتمل JOIN, APPLY, ، إلخ.)
  • WHERE
  • GROUP BY (يمكن إزالة التكرارات)
  • التجمعات
  • HAVING
  • وظائف النافذة
  • SELECT
  • DISTINCT (يمكن إزالة التكرارات)
  • UNION, INTERSECT, EXCEPT (يمكن إزالة التكرارات)
  • ORDER BY
  • OFFSET
  • LIMIT

كما ترون، فإن الترتيب المنطقي لكل عملية يؤثر على ما يمكن القيام به وكيف يؤثر على العمليات اللاحقة.على وجه الخصوص، حقيقة أن GROUP BY عملية "يحدث من قبل" ال SELECT العملية (الإسقاط) تعني أن:

  1. لا يعتمد على الإسقاط (والذي يمكن أن يكون ميزة)
  2. لا يمكن استخدام أي قيم من الإسقاط (والذي يمكن أن يكون عيبًا)

1.لا يعتمد على الإسقاط

أحد الأمثلة التي لا يكون فيها الاعتماد على الإسقاط مفيدًا إذا كنت تريد حساب وظائف النافذة على قيم مميزة:

SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating

عند تشغيل ضد قاعدة بيانات ساكيلا, ، هذه العوائد:

rating   rn
-----------
G        1
NC-17    2
PG       3
PG-13    4
R        5

لا يمكن تحقيق نفس الشيء مع DISTINCT بسهولة:

SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film

هذا الاستعلام "خاطئ" وينتج شيئًا مثل:

rating   rn
------------
G        1
G        2
G        3
...
G        178
NC-17    179
NC-17    180
...

هذا ليس ما أردناه.ال DISTINCT عملية "يحدث بعد" الإسقاط، لذلك لم يعد بإمكاننا إزالة DISTINCT التقييمات لأن وظيفة النافذة تم حسابها وعرضها بالفعل.لكي تستخدم DISTINCT, ، سيتعين علينا دمج هذا الجزء من الاستعلام:

SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
  SELECT DISTINCT rating FROM film
) f

ملاحظة جانبية: وفي هذه الحالة تحديدًا، يمكننا أيضًا استخدام DENSE_RANK()

SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film

2.لا يمكن استخدام أي قيم من الإسقاط

أحد عيوب SQL هو الإسهاب في بعض الأحيان.لنفس السبب الذي رأيناه من قبل (أي الترتيب المنطقي للعمليات)، لا يمكننا التجميع "بسهولة" حسب شيء نتوقعه.

هذا SQL غير صالح:

SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY name

هذا صحيح (تكرار التعبير)

SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY first_name || ' ' || last_name

وهذا صحيح أيضًا (تداخل التعبير)

SELECT name
FROM (
  SELECT first_name || ' ' || last_name AS name
  FROM customer
) c
GROUP BY name

لقد كتبت عن هذا الموضوع بتعمق أكبر في منشور بالمدونة

وأتوقع هناك إمكانية لالفروق الدقيقة في تنفيذها. راجعت خطط التنفيذ لمدة الاستفسارات يعادل وظيفيا على طول هذه الخطوط في أوراكل 10g:

core> select sta from zip group by sta;

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    58 |   174 |    44  (19)| 00:00:01 |
|   1 |  HASH GROUP BY     |      |    58 |   174 |    44  (19)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| ZIP  | 42303 |   123K|    38   (6)| 00:00:01 |
---------------------------------------------------------------------------

core> select distinct sta from zip;

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    58 |   174 |    44  (19)| 00:00:01 |
|   1 |  HASH UNIQUE       |      |    58 |   174 |    44  (19)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| ZIP  | 42303 |   123K|    38   (6)| 00:00:01 |
---------------------------------------------------------------------------

والعملية الوسطى هي مختلفة قليلا: "مجموعة HASH BY" مقابل "HASH UNIQUE"، ولكن التكاليف المقدرة وما هي متطابقة. وبعد ذلك تنفيذ هذه مع التتبع على وكانت التهم التشغيل الفعلي نفسها من أجل كل (باستثناء التي لم ثانية واحدة لم يكن لديك للقيام بأي المادية يقرأ بسبب التخزين المؤقت).

ولكن أعتقد أن لأسماء العملية مختلفة، تنفيذ ستتبع مختلفة بعض الشيء مسارات رمز والذي يفتح إمكانية المزيد من اختلافات كبيرة.

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

لالاستعلام قمت بنشرها، فهي متطابقة. ولكن بالنسبة للاستفسارات الأخرى التي قد لا يكون صحيحا.

وعلى سبيل المثال، انها ليست نفس:

SELECT C FROM myTbl GROUP BY C, D

وقرأت كل التعليقات الواردة أعلاه ولكن لا أرى أحدا وأشار إلى الفرق الرئيسي بين المجموعة حسب ومتميزة وبصرف النظر عن الشيء التجميع.

وعوائد متميزة كافة الصفوف ثم اجتثاث يكرر لهم في حين المجموعة بواسطة دي deduplicate الصفوف كما انهم قراءتها من قبل خوارزمية واحدا تلو الآخر.

وهذا يعني أنها يمكن أن تؤدي إلى نتائج مختلفة!

وعلى سبيل المثال، الرموز التالية تولد نتائج مختلفة:

SELECT distinct ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable

 SELECT ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable
GROUP BY Name

إذا هناك 10 أسماء في الجدول حيث 1 الذي هو نسخة مكررة من آخر ثم الاستعلام الأول إرجاع 10 صفوف في حين إرجاع الاستعلام الثاني 9 الصفوف.

والسبب هو ما قلته أعلاه بحيث أنها يمكن أن تتصرف بشكل مختلف!

إذا كنت تستخدم DISTINCT مع أعمدة متعددة، لن يتم تجميع مجموعة النتائج لأنها سوف مع GROUP BY، ولا يمكنك استخدام دالات التجميع مع DISTINCT.

ولديهم دلالات مختلفة، حتى لو كانوا موجودين ليكون لها نتائج تعادل على بيانات معينة.

وGROUP BY له معنى محدد للغاية والتي تختلف (هيه) من وظيفة متميزة.

وGROUP BY يتسبب في نتائج الاستعلام ليتم تجميعها باستخدام التعبير المختار، ومن ثم يمكن تطبيق وظائف الكلي، وهذه سوف تعمل على كل مجموعة، بدلا من resultset وكامل.

وهنا مثال التي قد تساعد:

وبالنظر إلى الجدول الذي يبدو مثل هذا:

name
------
barry
dave
bill
dave
dave
barry
john

وهذا الاستعلام:

SELECT name, count(*) AS count FROM table GROUP BY name;

هل إنتاج إخراج مثل هذا:

name    count
-------------
barry   2
dave    3
bill    1
john    1

والتي من الواضح مختلفة جدا من استخدام DISTINCT. إذا كنت ترغب في مجموعة النتائج، استخدم GROUP BY، إذا كنت ترغب فقط في قائمة فريدة من عمود معين، استخدم متميزة. هذا سيعطي قاعدة البيانات الخاصة بك فرصة لتحسين الاستعلام لاحتياجاتك.

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

إذا كنت تستخدم GROUP BY دون أي دالة تجميع ثم داخليا فإنه سيتم التعامل معها على أنها متميزة، حتى في هذه الحالة لا يوجد فرق بين GROUP BY ومتميزة.

ولكن عندما يتم توفير لكم مع شرط DISTINCT أفضل لاستخدامه للعثور على سجلات فريدة من نوعها لأن الهدف من GROUP BY هو تحقيق التجميع.

ومجموعة من يستخدم في العمليات الإجمالية - مثل عندما كنت ترغب في الحصول على عدد من فنادق صغيرة موزعة حسب العمود C

select C, count(B) from myTbl group by C

ومتميزة هو ما يبدو - تحصل صفوف فريدة

في مزود خدمة 2005، يبدو أن محسن الاستعلام قادر على تحسين بعيدا الفرق في الأمثلة المبسطة ركضت. دونو ما اذا كان يمكنك الاعتماد على ذلك في جميع الحالات، بالرغم من ذلك.

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

وومن "SQL لغة" وجهة نظر يبني هما أي ما يعادل واحد الذي اخترت واحدة من تلك الخيارات "نمط الحياة" علينا جميعا القيام بها. أعتقد أن هناك حالة جيدة لكائن DISTINCT أكثر وضوحا (وبالتالي هو أكثر مراعاة للشخص الذي سيرث التعليمات البرمجية الخ) ولكن هذا لا يعني أن GROUP BY بناء هو خيار غير صالح.

وأعتقد أن هذا 'GROUP BY هو بالنسبة للمجاميع' هو التركيز على خطأ. يجب أن تكون على علم القوم أن وظيفة مجموعة (MAX، MIN، عد، الخ) يمكن حذفها حتى يتمكنوا من فهم نية المبرمج عند التأكد من ذلك.

ومحسن المثالي سيتعرف بنيات SQL تعادل وسيختار دائما خطة مثالية وفقا لذلك. لديك محرك SQL الحياة الحقيقية في الاختيار، يجب اختبار:)

وPS ملاحظة موقف الكلمة واضحة في بند حدد قد تعطي نتائج مختلفة على سبيل المثال التباين:

SELECT COUNT(DISTINCT C) FROM myTbl;

SELECT DISTINCT COUNT(C) FROM myTbl;

في مقاومه منظور :

من وجهة نظر مجموعة نتائج للعرض، لا يهم إذا كنت تستخدم DISTINCT أو GROUP BY في مقاومه. مجموعة الجواب سوف تكون هي نفسها.

من وجهة نظر الأداء، فإنه ليست هي نفسها.

لفهم ما أداء الآثار، عليك أن تعرف ما يحدث على مقاومه عند تنفيذ بيان مع DISTINCT أو GROUP BY.

في حالة متميزة، وإعادة توزيع الصفوف على الفور دون أي preaggregation تجري، في حين أنه في حالة GROUP BY، في خطوة أولى تتم عملية preaggregation وعندها فقط هي القيم الفريدة توزيعها عبر تلك المكاتب.

لا أعتقد الآن أن GROUP BY الأفضل دائما من جهة نظر الأداء. عندما يكون لديك العديد من القيم المختلفة، فإن الخطوة preaggregation من GROUP BY ليست فعالة جدا. مقاومه لديها لفرز البيانات لإزالة التكرارات. في هذه الحالة، قد يكون من الأفضل لإعادة توزيع أولا، أي استخدام العبارة متميزة. إلا إذا كان هناك العديد من القيم المكررة، وGROUP BY بيان وربما كان الخيار الأفضل كما مرة واحدة فقط يأخذ خطوة إلغاء البيانات المكررة المكان، بعد إعادة التوزيع.

وباختصار، DISTINCT مقابل GROUP BY في مقاومه يعني:

وGROUP BY -> لكثير من التكرارات DISTINCT -> لا أو عدد قليل من التكرارات فقط. في بعض الأحيان، عند استخدام DISTINCT، كنت قد نفد من مساحة التخزين المؤقت على AMP. والسبب هو أن إعادة توزيع يحدث على الفور، ويمكن أن يسبب انحراف أمبير إلى نفاد الفضاء.

إذا حدث ذلك، ربما لديك فرصة أفضل مع GROUP BY، كما تتم إزالة مكررة من قبل في خطوة أولى، وسيتم نقل أقل البيانات عبر تلك المكاتب.

أنت يلاحظ فقط أن لأنك اختيار عمود واحد.

وحاول تحديد حقلين ونرى ما سيحدث.

والمقصود

والمجموعة حسب لاستخدامها مثل هذا:

SELECT name, SUM(transaction) FROM myTbl GROUP BY name

والتي من شأنها أن تظهر مجموع جميع المعاملات لكل شخص.

وأنا أعلم أنه في آخر العمر. ولكن يحدث أن كان لي استعلام الذي يستخدم مجموعة من فقط لإرجاع القيم متميزة عند استخدام هذا الاستعلام في الضفدع وتقارير أوراكل عملت كل شيء على ما يرام، أعني وقت استجابة جيدة. عندما هاجرنا من البيانات 9i Oracle إلى 11G كان زمن الاستجابة في العلجوم ممتاز ولكن في ما أوردته واستغرق حوالي 35 دقيقة لإنهاء التقرير عند استخدام الإصدار السابق استغرق الأمر حوالي 5 دقائق.

وكان الحل لتغيير المجموعة التي واستخدام DISTINCT والآن تشغيل التقرير في حوالي 30 ثانية.

وآمل أن يكون هذا مفيدا لشخص لديه نفس الوضع.

والطريق الأول دائما المفهوم هو أن استخدام متميزة هو نفس التجمع من قبل كل مجال قمت بتحديده في الترتيب الذي حددته لهم.

وأي بمعنى:

select distinct a, b, c from table;

وهو نفسه على النحو التالي:

select a, b, c from table group by a, b, c

وكفاءة Funtional مختلفة تماما. إذا كنت ترغب في اختيار فقط "قيمة الإرجاع" ما عدا واحدة مكررة، استخدم متميزة أفضل من مجموعة من. لأن "مجموعة من" تشمل (الفرز + إزالة)، "متميزة" تشمل (إزالة)

في خلية (HQL)، مجموعة من يمكن أن يكون وسيلة أسرع من متميزة، لأن الأول لا يتطلب مقارنة جميع الحقول في الجدول. انظر https://sqlperformance.com/2017 / 01 /-الاستفسارات T-SQL / مفاجآت-افتراضات مجموعة على حدة متميزة .

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

وحاول مثال بسيط

وتعلنtmpresult الجدول (   معرف tinyint )

وأدخل إلىtmpresult اختيار 5 الاتحاد جميع اختر 2 الاتحاد جميع اختر 3 الاتحاد جميع حدد 4

حدد متميزة هوية شخصية منtmpresult

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