Optymalizuję wiele istniejących zapytań w moim projekcie. Rozwiązanie Quassnoi bardzo pomogło mi przyspieszyć zapytania! Jednak trudno jest włączyć to rozwiązanie do wszystkich zapytań, szczególnie w przypadku skomplikowanych zapytań obejmujących wiele podzapytań na wielu dużych tabelach.
Dlatego używam mniej zoptymalizowanego rozwiązania. Zasadniczo działa tak samo, jak rozwiązanie Quassnoi.
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / [accomodation_table_row_count]
LIMIT $size
$size * $factor / [accomodation_table_row_count]
oblicza prawdopodobieństwo wybrania losowego wiersza. Rand () wygeneruje liczbę losową. Wiersz zostanie wybrany, jeśli rand () jest mniejszy lub równy prawdopodobieństwu. To skutecznie dokonuje losowego wyboru w celu ograniczenia rozmiaru tabeli. Ponieważ istnieje szansa, że zwróci mniej niż zdefiniowany limit liczby, musimy zwiększyć prawdopodobieństwo, aby upewnić się, że wybieramy wystarczającą liczbę wierszy. Dlatego mnożymy rozmiar $ przez współczynnik $ (zwykle ustawiam współczynnik $ = 2, działa w większości przypadków). Wreszcie robimylimit $size
Teraz problemem jest ustalenie accomodation_table_row_count . Jeśli znamy rozmiar tabeli, MOŻEMY na stałe zakodować rozmiar tabeli. To działałoby najszybciej, ale oczywiście nie jest to idealne rozwiązanie. Jeśli używasz Myisam, uzyskiwanie liczby stołów jest bardzo wydajne. Ponieważ używam innodb, po prostu robię proste liczenie + wybór. W twoim przypadku wyglądałoby to tak:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / (select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
Najtrudniejsze jest ustalenie odpowiedniego prawdopodobieństwa. Jak widać, poniższy kod w rzeczywistości oblicza tylko przybliżony rozmiar tabeli temp (w rzeczywistości jest zbyt przybliżony!): (select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category))
Ale możesz udoskonalić tę logikę, aby uzyskać bliższe przybliżenie rozmiaru tabeli. Zwróć uwagę, że lepiej jest zaznaczyć OVER niż niedostatecznie zaznaczyć wiersze. tzn. jeśli prawdopodobieństwo jest zbyt niskie, ryzykujesz, że nie wybierzesz wystarczającej liczby wierszy.
To rozwiązanie działa wolniej niż rozwiązanie Quassnoi, ponieważ musimy ponownie obliczyć rozmiar tabeli. Jednak uważam, że to kodowanie jest o wiele łatwiejsze w zarządzaniu. Jest to kompromis między dokładnością i wydajnością a złożonością kodowania . Powiedziawszy to, na dużych stołach jest to nadal znacznie szybsze niż Order by Rand ().
Uwaga: Jeśli pozwala na to logika zapytań, należy przeprowadzić losowy wybór możliwie jak najwcześniej przed wykonaniem jakichkolwiek operacji łączenia.