سؤال

عند استخدام SQL، هل هناك أي فوائد باستخدام = في WHERE جملة بدلا من LIKE?

دون أي مشغلين خاصين، LIKE و = هي نفسها، أليس كذلك؟

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

المحلول

مشغلين مختلفين

LIKE و = هم مختلف المشغلين. معظم الإجابات هنا تركز على دعم البدل، وهو ليس الفرق الوحيد بين هؤلاء المشغلين!

= هو مشغل المقارنة الذي يعمل على الأرقام والسلاسل. عند مقارنة السلاسل، يقارن مشغل المقارنة سلاسل كاملة.

LIKE هو مشغل سلسلة يقارن الشخصية حسب الشخصية.

لعقود الأمور، يستخدم كلا المشغلين التجميع والتي يمكن أن يكون لها آثار مهمة على نتيجة المقارنة.

مثال محفز

دعونا أولا تحديد مثال حيث ينتج هؤلاء المشغلون نتائج مختلفة بوضوح. اسمح لي بالاقتباس من دليل MySQL:

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

mysql> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
+-----------------------------------------+
| 'ä' LIKE 'ae' COLLATE latin1_german2_ci |
+-----------------------------------------+
|                                       0 |
+-----------------------------------------+
mysql> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
+--------------------------------------+
| 'ä' = 'ae' COLLATE latin1_german2_ci |
+--------------------------------------+
|                                    1 |
+--------------------------------------+

يرجى ملاحظة أن هذه الصفحة من دليل MySQL يسمى وظائف مقارنة السلسلة, ، و = لم تتم مناقشتها، مما يعني ذلك = ليست بدقة وظيفة مقارنة السلسلة.

كيف = الشغل؟

ال SQL Standard § 8.2 يصف كيف = يقارن السلاسل:

يتم تحديد مقارنة بين سلاسل حرفين على النحو التالي:

أ) إذا كان الطول الموجود في حرف X لا يساوي الطول في أحرف y، فسيتم استبدال السلسلة الأقصر بشكل فعال، لأغراض المقارنة، مع نسخة من نفسها تم تمديدها إلى طول السلسلة الطويلة بسلسلة على يمين شخصيات وسادة واحدة أو أكثر، حيث يتم اختيار حرف الوسادة بناء على CS. إذا كانت CS لديها سمة No Pad، فإن حرف الوسادة عبارة عن شخصية تعتمد على التنفيذ تختلف عن أي حرف في مجموعة الأحرف من X و Y التي تتولى أقل من أي سلسلة تحت CS. خلاف ذلك، شخصية الوسادة هي.

ب) نتيجة للمقارنة بين x و y تعطى من قبل تسلسل cs.

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

(تم اضافة التأكيدات.)

ماذا يعني هذا؟ وهذا يعني أنه عند مقارنة السلاسل، = المشغل هو مجرد غلاف رقيق حول الترتيب الحالي. الترتيب عبارة عن مكتبة لديها قواعد مختلفة لمقارنة السلاسل. هنا مثال على تجميع ثنائي من mysql:

static int my_strnncoll_binary(const CHARSET_INFO *cs __attribute__((unused)),
                               const uchar *s, size_t slen,
                               const uchar *t, size_t tlen,
                               my_bool t_is_prefix)
{
  size_t len= MY_MIN(slen,tlen);
  int cmp= memcmp(s,t,len);
  return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
}

يحدث هذا الترتيب المحدد مقارنة بايت بايت (وهذا هو السبب في أنه يطلق عليه "ثنائي" - لا يعطي أي معنى خاص للأسلوت). قد توفر مجموعات أخرى مقارنات أكثر تقدما.

على سبيل المثال، هنا UTF-8 تجميع هذا يدعم مقارنات غير حساسة للحالة. الرمز طويل جدا للصق هنا، ولكن انتقل إلى هذا الرابط وقراءة الجسم my_strnncollsp_utf8mb4(). وبعد يمكن لهذا الترتيب معالجة بايت متعددة في كل مرة ويمكنه تطبيق تحويلات مختلفة (مثل مقارنة غير حساسة للحالة). ال = يتم تجريد المشغل بالكامل من إغراق الترتيب.

كيف LIKE الشغل؟

ال SQL القياسية § 8.5 يصف كيف LIKE يقارن السلاسل:

الu003Cpredicate>

M LIKE P

صحيح إذا كان هناك تقسيم م في السلاحيات بحيث:

1) فرعية من م هي تسلسل من 0 أو أكثر متجاورةu003Ccharacter representation> ق من م وكلu003Ccharacter n representation> من م هي جزء من فرعية واحدة بالضبط.

ثانيا) إذا كان جهاز الإعدادات الفرعية I-TH من P هو محدد شخصيات تعسفية، فإن فرعية I-TH من M هي أي واحدةu003Ccharacter representation> وبعد

III) إذا كان جهاز الإعدادات الفرعية I-TH من P هو محدد سلسلة تعسفية، فإن السلافة i-th i's هي أي تسلسل من 0 أو أكثرu003Ccharacter representation> س.

رابعا) إذا لم يكن جهاز تحديد المستوى الأول من P محركات حرف تعسفية ولا محدد سلسلة تعسفية، فإن فرعية i-th i-tr trasing مساوية لتلك المواصفات الفرعية وفقا لتسلسل Collating of theu003Clike predicate> ، دون إلحاقu003Cspace> الأحرف إلى م، ولها نفس الطول كما هو محدد الفرشاة.

خامسا) عدد الأستبد من م يساوي عدد محددات فرعية من P.

(تم اضافة التأكيدات.)

هذا هو هود جدا، لذلك دعونا اقتحامها. البنود II و III الرجوع إلى أحرف البدل _ و %, ، على التوالى. إذا P لا يحتوي على أي أحرف البدل، ثم ينطبق العنصر الرابع فقط. هذه هي حالة الفائدة التي تطرحها المرجع.

في هذه الحالة، يقارن كل "Substring" (أحرف فردية) في M ضد كل فرعية في P باستخدام الترتيب الحالي.

الاستنتاجات

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

التي ينبغي لأحد أن تستخدمها؟ لا أحد يستطيع أن يخبرك بذلك - تحتاج إلى استخدام واحد صحيح لحالة استخدامك. لا تتحسن قبل الأوان بواسطة مشغلي المقارنة.

نصائح أخرى

المشغل المستقيم (=) هو "مشغل المقارنة يقارن قيمين للمساواة." بمعنى آخر، في عبارة SQL، لن يعود الأمر صحيحا ما لم تكن جانبي المعادلة متساوية. علي سبيل المثال:

SELECT * FROM Store WHERE Quantity = 200;

يعمل المشغل المتطور "ينفذ مقارنة مطابقة نمط" تحاول مطابقة "قيمة السلسلة مقابل سلسلة نمط تحتوي على أحرف بطاقة برية." علي سبيل المثال:

SELECT * FROM Employees WHERE Name LIKE 'Chris%';

مثل يستخدم عموما فقط مع سلاسل ويساوي (أعتقد) أسرع. يعامل المشغل المساوي شخصيات البطاقة البرية كحرف حرفية. الفرق في النتائج التي تم إرجاعها هي كما يلي:

SELECT * FROM Employees WHERE Name = 'Chris';

و

SELECT * FROM Employees WHERE Name LIKE 'Chris';

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

SELECT * FROM Employees WHERE Name = 'Chris%';

و

SELECT * FROM Employees WHERE Name LIKE 'Chris%';

سيعود نتائج مختلفة، حيث تستخدم "=" النتائج فقط بنتائج "كريس٪" التي يتم إرجاعها، وسوف يعيد المشغل المتثل أي شيء يبدأ ب "كريس".

امل ان يساعد. يمكن العثور على بعض المعلومات الجيدة هنا.

LIKE و = مختلفة. LIKE هو ما سوف تستخدمه في استعلام البحث. كما يسمح بحذر البدل _ (حرف البدل البسيطة) و % (البدل متعدد الأحرف).

= يجب أن تستخدم إذا كنت تريد التطابقات الدقيقة وسوف تكون أسرع.

يشرح هذا الموقع LIKE

هذه نسخة / لصق إجابة أخرى من الألغام للسؤال SQL "مثل" VS "= الأداء:

مثال شخصي باستخدام MySQL 5.5: كان لدي انضمام داخلي بين طاولتين، واحدة من 3 ملايين صفوف واحد من 10 آلاف صف.

عند استخدام مثل في فهرس على النحو التالي (بدون أحرف البدل)، استغرق الأمر حوالي 30 ثانية:

where login like '12345678'

باستخدام "شرح" أحصل عليه:

enter image description here

عند استخدام "=" على نفس الاستعلام، استغرق الأمر حوالي 0.1 ثانية:

where login ='12345678'

باستخدام "شرح" أحصل عليه:

enter image description here

كما ترون، like ألغيت تماما المسعى الفهرس، لذلك استغرق الاستعلام 300 مرة المزيد من الوقت.

فرق واحد - بصرف النظر عن إمكانية استخدام أحرف البدل مع مثل - في مسافات زائدة: يتجاهل المشغل مساحة زائدة، ولكن مثل لا.

يعتمد على نظام قاعدة البيانات.

بشكل عام مع عدم وجود أحرف خاصة، نعم، وما شابه ذلك هو نفسه.

ومع ذلك، قد تعالج بعض أنظمة قاعدة البيانات إعدادات الترتيب بشكل مختلف مع المشغلين المختلفين.

على سبيل المثال، في مقارنات MySQL مع = السلاسل هي دائما غير حساسة لحالة الأحرف بشكل افتراضي، مثل أي شخصيات خاصة هي نفسها. على بعض RDBMS الأخرى مثل غير حساس في حالة = ليس كذلك.

لهذا المثال، نأخذها أمرا مفروغا منه أن varcharcol لا يحتوي '' وليس لديهم خلية فارغة ضد هذا العمود

select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''

أول واحد ينتج عنه 0 خرج الصف بينما يظهر المرء الثاني القائمة بأكملها. = حالة مطابقة بدقة أثناء تصرفات مثل مرشح. إذا كان المرشح ليس لديه معايير، كل بيانات صالحة.

مثل - بفضل هدفها يعمل أبطأ قليلا ويهدف للاستخدام مع Varchar وبيانات مماثلة.

إذا كنت تبحث عن مطابقة محددة، يمكنك استخدام كل من كليهما، وما شابه ذلك.

باستخدام "=" هو أسرع قليلا في هذه الحالة (البحث عن مطابقة محددة) - يمكنك التحقق من ذلك بنفسك من خلال وجود نفس الاستعلام مرتين في SQL Server Management Studio، بمجرد استخدام "="، بمجرد استخدام "مثل" و ثم استخدام "الاستعلام" / "تشمل خطة التنفيذ الفعلية".

تنفيذ الاستعلامات ويجب أن ترى نتائجك مرتين، بالإضافة إلى خطط التنفيذ الفعلية. في حالتي، تم تقسيمها بنسبة 50٪ مقابل 50٪، ولكن خطة التنفيذ "=" تحتوي على "تكلفة فرعية تقدر متقدمة" (يتم عرضها عند تحريكها عبر مربع "تحديد" الأيسر) - ولكن مرة أخرى، إنه حقا ليس فرقا كبيرا.

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

مارك

باستخدام = تجنب أحرف البدل والشخصيات الخاصة تعارض في السلسلة عند إنشاء الاستعلام في وقت التشغيل.

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

لفات العينين في '90s

كما أشك في أنها أبطأ قليلا، لكنني أشك في أنها مهمة إذا لم تكن هناك أحرف البدل في النمط.

لمعالجة السؤال الأصلي فيما يتعلق بالأداء، يتعلق الأمر استخدام الفهرس. وبعد عند حدوث فحص جدول بسيط، "مثل" و "=" تطابق. وبعد عندما تشارك الفهارس، فإنه يعتمد على على كيفية تشكيل جملة مثل. وبشكل أكثر تحديدا، ما هو موقع Wildcard (S)؟


النظر فيما يلي:

CREATE TABLE test(
    txt_col  varchar(10) NOT NULL
)
go

insert test (txt_col)
select CONVERT(varchar(10), row_number() over (order by (select 1))) r
  from master..spt_values a, master..spt_values b
go

CREATE INDEX IX_test_data 
    ON test (txt_col);
go 

--Turn on Show Execution Plan
set statistics io on

--A LIKE Clause with a wildcard at the beginning
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '%10000'
--Results in
--Table 'test'. Scan count 3, logical reads 15404, physical reads 2, read-ahead reads 15416, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index SCAN is 85% of Query Cost

--A LIKE Clause with a wildcard in the middle
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '1%99'
--Results in
--Table 'test'. Scan count 1, logical reads 3023, physical reads 3, read-ahead reads 3018, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost for test data, but it may result in a Table Scan depending on table size/structure

--A LIKE Clause with no wildcards
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO

--an "=" clause = does Index Seek same as above
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col = '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO


DROP TABLE test

قد يكون هناك اختلاف ضئيل أيضا في إنشاء خطة الاستعلام عند استخدام "=" مقابل "مثل".

إلى جانب البدل، الفرق بين = و LIKE سوف تعتمد على كل من نوع خادم SQL وعلى نوع العمود.

خذ هذا المثال:

CREATE TABLE testtable (
  varchar_name VARCHAR(10),
  char_name CHAR(10),
  val INTEGER
);

INSERT INTO testtable(varchar_name, char_name, val)
    VALUES ('A', 'A', 10), ('B', 'B', 20);

SELECT 'VarChar Eq Without Space', val FROM testtable WHERE varchar_name='A'
UNION ALL
SELECT 'VarChar Eq With Space', val FROM testtable WHERE varchar_name='A '
UNION ALL
SELECT 'VarChar Like Without Space', val FROM testtable WHERE varchar_name LIKE 'A'
UNION ALL
SELECT 'VarChar Like Space', val FROM testtable WHERE varchar_name LIKE 'A '
UNION ALL
SELECT 'Char Eq Without Space', val FROM testtable WHERE char_name='A'
UNION ALL
SELECT 'Char Eq With Space', val FROM testtable WHERE char_name='A '
UNION ALL
SELECT 'Char Like Without Space', val FROM testtable WHERE char_name LIKE 'A'
UNION ALL
SELECT 'Char Like With Space', val FROM testtable WHERE char_name LIKE 'A '
  • استخدام MS SQL Server 2012, ، سيتم تجاهل المساحات الزائدة في المقارنة، إلا مع LIKE عندما يكون نوع العمود VARCHAR.

  • استخدام MySQL 5.5., ، سيتم تجاهل المساحات الزائدة ل =, ، ولكن ليس ل LIKE, ، سواء مع CHAR و VARCHAR.

  • استخدام postgresql 9.1., ، المساحات مهمة مع كليهما = و LIKE استخدام VARCHAR, ، ولكن ليس مع CHAR (يرى توثيق).

    السلوك مع LIKE يختلف أيضا مع CHAR.

    باستخدام نفس البيانات على النحو الوارد أعلاه، باستخدام صريح CAST على اسم العمود أيضا يجعل الفرق:

    SELECT 'CAST none', val FROM testtable WHERE char_name LIKE 'A'
    UNION ALL
    SELECT 'CAST both', val FROM testtable WHERE
        CAST(char_name AS CHAR) LIKE CAST('A' AS CHAR)
    UNION ALL
    SELECT 'CAST col', val FROM testtable WHERE CAST(char_name AS CHAR) LIKE 'A'
    UNION ALL
    SELECT 'CAST value', val FROM testtable WHERE char_name LIKE CAST('A' AS CHAR)
    

    هذا فقط إرجاع الصفوف "يلقي كليها" و "col col".

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

مع أطيب التحيات...

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

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

= و LIKE ليس هو نفسه؛

  1. = يطابق السلسلة الدقيقة
  2. LIKE يطابق سلسلة قد تحتوي على أحرف البدل (٪)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top