/ / Optymalizacja połączonych wyników za pomocą klauzuli Order By - mysql, optymalizacja zapytań

Optymalizacja wyników JOINED z klauzulą ​​Order By - mysql, optymalizacja zapytań

Rozważ następujący schemat (dostępny na sqlFiddle)

create table ad (
id int primary key auto_increment,
category_id int,
city_id int,
name varchar(255),
key(category_id),
key(city_id)
);

create table category (
id int primary key auto_increment,
name varchar(255)
);

create table city (
id int primary key auto_increment,
name varchar(255)
);

insert into category values (null, "Category 1");
insert into category values (null, "Category 2");
insert into category values (null, "Category 3");

insert into city values (null, "City 1");
insert into city values (null, "City 2");

insert into ad values (null, 1, 1, "Category 1 city 1");
insert into ad values (null, 1, 2, "Category 1 city 2");
insert into ad values (null, 2, 1, "Category 2 city 1");
insert into ad values (null, 2, 2, "Category 2 city 2");
insert into ad values (null, 3, 1, "Category 3 city 1");
insert into ad values (null, 3, 2, "Category 3 city 2");

Podczas wykonywania prostego połączonego zapytania bez zamówienia według:

SELECT ad.id, ad.name, category.name, city.name FROM ad
INNER JOIN category ON category.id = ad.category_id
INNER JOIN city ON city.id = ad.city_id

wynik jest dość wydajny:

wprowadź opis obrazu tutaj

Jednak jak tylko dodam klauzulę ORDER BY, następuje tymczasowe sortowanie tabel i plików:

SELECT ad.id, ad.name, category.name, city.name FROM ad
INNER JOIN category ON category.id = ad.category_id
INNER JOIN city ON city.id = ad.city_id
ORDER BY ad.id

wprowadź opis obrazu tutaj

Jak zoptymalizować takie zapytanie?

Odpowiedzi:

0 dla odpowiedzi № 1

Możesz użyć STRAIGTH_JOIN.

SELECT STRAIGHT_JOIN ad.id, ad.name, category.name, city.name FROM ad
INNER JOIN category ON category.id = ad.category_id
INNER JOIN city ON city.id = ad.city_id
ORDER BY ad.id

Optymalizator MySQL wybrał dostęp do tabeli w niewłaściwej kolejności (miasto, reklama, kategoria) optymalną kolejnością dostępu byłaby (reklama, kategoria, miasto) STRAIGTH_JOIN wymusiłby dostęp do tabeli.


0 dla odpowiedzi nr 2

Przedwczesna panika. Przy tak niewielu rzędach EXPLAIN „t” nie udowodni, że plan zapytań nie jest dobry. Z tysiącem reklam i dziesiątkami miast i kategorii Optymalizator może wybrać ad jako pierwszy stół do pracy.

Optymalizator również nie wie, czy Twoje tabele to 1 reklama - wiele kategorii i miast. Lub wielu: wielu.

Skarżyłeś się, bo wiesz, że każdy ad jest tylko w jednej kategorii i jednym mieście?

„BNL” i „korzystanie z bufora dołączania” są dość wydajnymi sposobami wykonywania zapytań - ładują wszystko, a następnie manipulują nimi w wydajny sposób w pamięci RAM.

Ponadto „Korzystanie z plików tymczasowych” i „Korzystanie z plików” nie jest aż tak złe, jak się wydaje. To jest zazwyczaj wykonane w pamięci RAM za pomocą wydajnego „qsort” w pamięci.


-1 dla odpowiedzi nr 3

Sam udało mi się znaleźć rozwiązanie. Przede wszystkim należy skutecznie obliczyć wymagane identyfikatory z głównej tabeli (ich filtrowanie i sortowanie), a następnie po prostu ponownie połączyć wyniki z tymi kluczami w wewnętrznym zapytaniu:

SELECT ad.id, ad.name, category.name, city.name FROM
(
SELECT id FROM ad WHERE price <= 3000 ORDER BY id DESC
) AS v
JOIN ad ON v.id = ad.id
JOIN category ON category.id = ad.category_id
JOIN city ON city.id = ad.city_id

Jest oczywiście więcej kolumn zaangażowanych w moją pracęwalizka. Przy takim zapytaniu (zawierającym 60 000 rekordów w głównej tabeli) szybkość wykonywania wzrosła z 0,16 do 0,004 s, o ile posortuję według indeksowanych kolumn.