Mysql
 sql >> база данни >  >> RDS >> Mysql

Редът на полетата в клауза WHERE влияе ли на производителността в MySQL?

SQL е проектиран да бъде декларативен език, а не процедурен. Така че оптимизаторът на заявки трябва да не вземете предвид реда на предикатите на клаузата where, когато определяте как да ги приложите.

Вероятно ще опростя твърде много следната дискусия за оптимизатор на SQL заявки. Написах преди една година, по този начин (беше много забавно!). Ако наистина искате да се задълбочите в съвременната оптимизация на заявки, вижте SQL настройка , от O'Reilly.

В обикновен оптимизатор на SQL заявки SQL изразът първо се компилира в дърво от релационна алгебра операции. Всяка от тези операции приема една или повече таблици като вход и произвежда друга таблица като изход. Сканиране е последователно сканиране, което чете таблица от базата данни. Сортиране създава сортирана таблица. Изберете произвежда таблица, чиито редове са избрани от друга таблица според някакво условие за избор. Проект създава таблица само с определени колони от друга таблица. Кръстосан продукт взема две таблици и създава изходна таблица, съставена от всяко възможно сдвояване на техните редове.

Объркващо е, че клаузата SELECT на SQL е компилирана в релационна алгебра Проект , докато клаузата WHERE се превръща в релационна алгебра Select . Клаузата FROM се превръща в едно или повече Присъединявания , като всеки взема две маси и произвежда една маса. Има и други операции на релационна алгебра, включващи обединение на множество, пресичане, разлика и членство, но нека да останем прости.

Това дърво наистина трябва да бъде оптимизирано. Например, ако имате:

select E.name, D.name 
from Employee E, Department D 
where E.id = 123456 and E.dept_id = D.dept_id

с 5000 служители в 500 отдела, изпълнението на неоптимизирано дърво ще произведе сляпо всички възможни комбинации от един служител и един отдел (Крос продукт ) и след това Изберете извадете само една комбинация, която беше необходима. Сканиране of Employee ще създаде таблица с 5000 записи, Сканиране на отдел ще създаде таблица с 500 записи, Кръстосаният продукт от тези две таблици ще създаде таблица с 2 500 000 записи, а Избор на E.id ще вземе тази таблица от 2 500 000 записи и ще изхвърли всички, освен един, записа, който беше търсен.

[Разбира се, реалните процесори на заявки ще се опитат да не материализират всички тези междинни таблици в паметта.]

Така оптимизаторът на заявки върви по дървото и прилага различни оптимизации. Единият е да разбиете всеки Select във верига от Избирания , по един за всеки от оригиналните Избор условия на най-високо ниво, тези и-издадени заедно. (Това се нарича "конюнктивна нормална форма".) След това отделният по-малък Избира се преместват в дървото и се сливат с други операции на релационна алгебра, за да образуват по-ефективни.

В горния пример оптимизаторът първо натиска Избор на E.id =123456 по-долу под скъпия Кръстосан продукт операция. Това означава Кръстосаният продукт просто произвежда 500 реда (по един за всяка комбинация от този служител и един отдел). След това най-горното ниво Избор for E.dept_id =D.dept_id филтрира 499 нежелани реда. Не е лошо.

Ако има индекс в полето ID на служителя, тогава оптимизаторът може да комбинира Сканиране на служител с Избор на E.id =123456 за образуване на бърз индекс Търсене . Това означава, че само един ред Employee се чете в паметта от диск вместо 5000. Нещата се подобряват.

Последната основна оптимизация е да вземете Избор на E.dept_id =D.dept_id и го комбинирайте с Кръстосания продукт . Това го превръща в релационна алгебра Equijoin операция. Това не прави много само по себе си. Но ако има индекс на Department.dept_id, тогава последователното Сканиране на по-ниско ниво на отдел, захранващ Equijoin може да се превърне в много бърз индекс Търсене от записите на отдела на нашия един служител.

По-малките оптимизации включват натискане на Проект операции надолу. Ако най-горното ниво на вашата заявка се нуждае само от E.name и D.name, а условията се нуждаят от E.id, E.dept_id и D.dept_id, тогава Сканиране операциите не трябва да изграждат междинни таблици с всички останали колони, спестявайки място по време на изпълнението на заявката. Превърнахме ужасно бавна заявка в две търсения в индекс и не много друго.

Приближавайки се повече към оригиналния въпрос, да кажем, че имате:

select E.name 
from Employee E 
where E.age > 21 and E.state = 'Delaware'

Неоптимизираното дърво на релационна алгебра, когато се изпълни, ще сканира 5000 служители и ще произведе, да речем, 126-те в Делауеър, които са на възраст над 21 години. Оптимизаторът на заявки също има някаква груба представа за стойностите в базата данни. Може да знае, че колоната E.state има 14-те щата, в които компанията има местоположения, и нещо за дистрибуциите на E.age. Така че първо вижда дали някое поле е индексирано. Ако E.state е, има смисъл да използвате този индекс, за да изберете само малкия брой служители, за които процесорът на заявки подозира, че са в Делауеър въз основа на последните изчислени статистически данни. Ако е само E.age, процесорът на заявки вероятно решава, че не си струва, тъй като 96% от всички служители са на 22 и повече години. Така че, ако E.state е индексиран, нашият процесор на заявки нарушава Select и обединява E.state ='Delaware' с Сканиране за да го превърнете в много по-ефективно Индексно сканиране .

Да кажем в този пример, че няма индекси за E.state и E.age. Комбинираният Избор операцията се извършва след последователното "сканиране" на служител. Има ли разлика кое условие в Избор се прави първо? Вероятно не е много. Процесорът на заявки може да ги остави в оригиналния ред в SQL израза или може да е малко по-усъвършенстван и да погледне очакваните разходи. От статистиката отново ще открие, че условието E.state ='Delaware' трябва да бъде по-силно селективно, така че ще обърне условията и ще направи това първо, така че да има само 126 E.age> 21 сравнения вместо 5000 . Или може да разбере, че сравненията за равенство на низове са много по-скъпи от сравненията с цели числа и да остави реда на мира.

Във всеки случай всичко това е много сложно и редът на синтактични условия е много малко вероятно да има разлика. Не бих се тревожил за това, освен ако нямате реален проблем с производителността и вашият доставчик на база данни използва реда на условието като намек.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL заявка, където полето НЕ съдържа $x

  2. Съпоставяне на JDBC ResultSet към обект

  3. Ред на изтриване с ограничения на външния ключ,

  4. MySQL подниз между два низа

  5. NHibernate IPreUpdateEventListener, IPreInsertEventListener не се записва в DB