Ograniczając liczbę wierszy zwracanych przez zapytanie SQL, zwykle używaną w stronicowaniu, istnieją dwie metody określania łącznej liczby rekordów:
Metoda 1
Uwzględnij SQL_CALC_FOUND_ROWS
opcję w oryginale SELECT
, a następnie uzyskaj łączną liczbę wierszy, uruchamiając SELECT FOUND_ROWS()
:
SELECT SQL_CALC_FOUND_ROWS * FROM table WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();
Metoda 2
Uruchom zapytanie normalnie, a następnie uzyskaj łączną liczbę wierszy, uruchamiając SELECT COUNT(*)
SELECT * FROM table WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM table WHERE id > 100;
Która metoda jest najlepsza / najszybsza?
źródło
SQL_CALC_FOUND_ROWS
zajęło ponad 20 sekund; użycie osobnegoCOUNT(*)
zapytania zajęło mniej niż 5 sekund (w przypadku zapytań licznik + wyniki).SQL_CALC_FOUND_ROWS
będzie to szybsze, zastanawiam się, w jakich sytuacjach (jeśli w ogóle) faktycznie jest szybsze!tblA
,tblB
,tblC
,tblD
,tblY
GDZIE tblA.b = tblC.id AND tblA.c = tblB.id AND tblA.d = tblD.id AND tblA.y = tblY.idid
), zajęło tylko 0,25.FOUND_ROWS()
w MySQL 8.0.17 jest to przestarzałe. Zobacz także odpowiedź @ madhur-bhaiya.Wybierając „najlepsze” podejście, ważniejszą kwestią niż szybkość może być łatwość utrzymania i poprawność kodu. Jeśli tak, SQL_CALC_FOUND_ROWS jest preferowany, ponieważ potrzebujesz tylko jednego zapytania. Użycie pojedynczego zapytania całkowicie wyklucza możliwość subtelnej różnicy między zapytaniem głównym i licznikiem, co może prowadzić do niedokładnego COUNT.
źródło
MySQL zaczął wycofywać swoją
SQL_CALC_FOUND_ROWS
funkcjonalność od wersji 8.0.17 i nowszych.Dlatego zawsze lepiej jest rozważyć wykonanie zapytania za pomocą
LIMIT
, a następnie drugiego zapytania zCOUNT(*)
lub bez wLIMIT
celu określenia, czy są dodatkowe wiersze.Z dokumentów :
SQL_CALC_FOUND_ROWS
Zaobserwowano również, że ogólnie ma więcej problemów, jak wyjaśniono w MySQL WL # 12615 :źródło
LOCK TABLES <tablename>
iUNLOCK TABLES
. Trzecią opcją i (najlepszym IMHO) jest przemyślenie paginacji. Przeczytaj: mariadb.com/kb/en/library/pagination-optimizationZgodnie z następującym artykułem: https://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
Jeśli masz INDEX w swojej klauzuli Where (jeśli id jest indeksowany w twoim przypadku), lepiej nie używać SQL_CALC_FOUND_ROWS i zamiast tego używać 2 zapytań, ale jeśli nie masz indeksu tego, co umieściłeś w swojej klauzuli Where (id w twoim przypadku), to użycie SQL_CALC_FOUND_ROWS jest bardziej wydajne.
źródło
IMHO, powód, dla którego 2 zapytania
są szybsze niż używanie SQL_CALC_FOUND_ROWS
należy traktować jako szczególny przypadek.
W rzeczywistości zależy to od selektywności klauzuli WHERE w porównaniu z selektywnością klauzuli niejawnej odpowiadającej ORDER + LIMIT.
Jak powiedział Arvids w komentarzu ( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-1174394 ), fakt, że EXPLAIN używa lub nie, tabela tymczasowa powinna być dobrą podstawą do ustalenia, czy SCFR będzie szybszy, czy nie.
Ale, jak dodałem ( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-8166482 ), wynik naprawdę zależy od przypadku. W przypadku konkretnego paginatora możesz dojść do wniosku, że „dla 3 pierwszych stron użyj 2 zapytań; na kolejnych stronach użyj SCFR ”!
źródło
Usunięcie niepotrzebnego kodu SQL i wtedy
COUNT(*)
będzie szybsze niżSQL_CALC_FOUND_ROWS
. Przykład:Następnie policz bez zbędnej części:
źródło
Istnieją inne opcje testów porównawczych:
1.) Funkcja okna bezpośrednio zwraca rzeczywisty rozmiar (testowane w MariaDB):
2.) Myśląc po wyjęciu z pudełka, przez większość czasu użytkownicy nie muszą znać DOKŁADNEGO rozmiaru stołu, przybliżenie jest często wystarczające.
źródło