어느 것이 가장 빠릅니까? `table`에서 SELECT SQL_CALC_FOUND_ROWS 또는 SELECT COUNT (*)
일반적으로 페이징에 사용되는 SQL 쿼리에 의해 리턴되는 행 수를 제한하는 경우 총 레코드 수를 판별하는 두 가지 방법이 있습니다.
방법 1
SQL_CALC_FOUND_ROWS
original에 옵션을 포함 SELECT
시키고 다음을 실행하여 총 행 수를 가져옵니다 SELECT FOUND_ROWS()
.
SELECT SQL_CALC_FOUND_ROWS * FROM table WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();
방법 2
쿼리를 정상적으로 실행 한 다음 다음을 실행하여 총 행 수를 얻습니다. SELECT COUNT(*)
SELECT * FROM table WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM table WHERE id > 100;
어떤 방법이 최고 / 가장 빠릅니까?
때에 따라 다르지. 이 주제에 대한 MySQL 성능 블로그 게시물을 참조하십시오 : http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
간단히 요약하자면 Peter는 색인과 기타 요인에 따라 달라집니다. 게시물에 대한 많은 의견은 SQL_CALC_FOUND_ROWS가 두 개의 쿼리를 실행하는 것보다 거의 항상 느리며 때로는 최대 10 배까지 느리다고 말합니다.
"최상의"접근 방식을 선택할 때 속도보다 더 중요한 고려 사항은 코드의 유지 관리 성과 정확성입니다. 그렇다면 단일 쿼리 만 유지하면되므로 SQL_CALC_FOUND_ROWS가 선호됩니다. 단일 쿼리를 사용하면 기본 쿼리와 개수 쿼리 사이에 미묘한 차이가 생길 수 있으므로 COUNT가 부정확 할 수 있습니다.
다음 기사에 따르면 https://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
where 절에 INDEX 가있는 경우 (ID가 색인 인 경우) SQL_CALC_FOUND_ROWS 를 사용하지 않고 2 개의 쿼리를 대신 사용하는 것이 좋지만 where 절에 넣은 것에 대한 색인이없는 경우 (귀하의 경우 id) SQL_CALC_FOUND_ROWS 를 사용하는 것이 더 효율적입니다.
IMHO, 2 개의 쿼리가 필요한 이유
SELECT * FROM count_test WHERE b = 666 ORDER BY c LIMIT 5;
SELECT count(*) FROM count_test WHERE b = 666;
SQL_CALC_FOUND_ROWS를 사용하는 것보다 빠릅니다.
SELECT SQL_CALC_FOUND_ROWS * FROM count_test WHERE b = 555 ORDER BY c LIMIT 5;
특별한 경우로보아야합니다.
실제로 ORDER + LIMIT와 동등한 내재 된 항목의 선택 성과 비교 한 WHERE 절의 선택성에 따라 달라집니다.
Arvids가 의견 ( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-1174394 ) 에서 언급했듯이 EXPLAIN이 사용하는지 여부는 템포 레이 테이블은 SCFR이 더 빠른지 아닌지를 알기에 좋은 기반이되어야합니다.
그러나 ( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-8166482 )를 추가 했으므로 결과는 실제로 사례에 따라 다릅니다. 특정 페이지 매김 자에 대해 다음과 같은 결론을 얻을 수 있습니다. 다음 페이지에 대해서는 SCFR을 사용하십시오.”!
불필요한 SQL을 제거하면 COUNT(*)
보다 빠릅니다 SQL_CALC_FOUND_ROWS
. 예:
SELECT Person.Id, Person.Name, Job.Description, Card.Number
FROM Person
JOIN Job ON Job.Id = Person.Job_Id
LEFT JOIN Card ON Card.Person_Id = Person.Id
WHERE Job.Name = 'WEB Developer'
ORDER BY Person.Name
그런 다음 불필요한 부분없이 계산하십시오.
SELECT COUNT(*)
FROM Person
JOIN Job ON Job.Id = Person.Job_Id
WHERE Job.Name = 'WEB Developer'
MySQL은 SQL_CALC_FOUND_ROWS
8.0.17 이후 버전에서 기능을 더 이상 사용하지 않습니다 .
따라서 항상을 사용 하여 쿼리를 실행 LIMIT
한 다음 추가 행이 있는지 여부를 결정 COUNT(*)
하지 않고 두 번째 쿼리를 실행하는 것이 좋습니다LIMIT
.
에서 문서 :
SQL_CALC_FOUND_ROWS 쿼리 수정 자와 함께 제공되는 FOUND_ROWS () 함수는 MySQL 8.0.17부터 더 이상 사용되지 않으며 향후 MySQL 버전에서 제거 될 예정입니다.
COUNT (*)는 특정 최적화 대상입니다. SQL_CALC_FOUND_ROWS로 인해 일부 최적화가 비활성화됩니다.
대신 다음 쿼리를 사용하십시오.
SELECT * FROM tbl_name WHERE id > 100 LIMIT 10; SELECT COUNT(*) WHERE id > 100;
또한 MySQL WL # 12615SQL_CALC_FOUND_ROWS
에서 설명한 것처럼 일반적으로 더 많은 문제가있는 것으로 관찰되었습니다 .
SQL_CALC_FOUND_ROWS has a number of problems. First of all, it's slow. Frequently, it would be cheaper to run the query with LIMIT and then a separate SELECT COUNT() for the same query, since COUNT() can make use of optimizations that can't be done when searching for the entire result set (e.g. filesort can be skipped for COUNT(*), whereas with CALC_FOUND_ROWS, we must disable some filesort optimizations to guarantee the right result)
More importantly, it has very unclear semantics in a number of situations. In particular, when a query has multiple query blocks (e.g. with UNION), there's simply no way to calculate the number of “would-have-been” rows at the same time as producing a valid query. As the iterator executor is progressing towards these kinds of queries, it is genuinely difficult to try to retain the same semantics. Furthermore, if there are multiple LIMITs in the query (e.g. for derived tables), it's not necessarily clear to which of them SQL_CALC_FOUND_ROWS should refer to. Thus, such nontrivial queries will necessarily get different semantics in the iterator executor compared to what they had before.
Finally, most of the use cases where SQL_CALC_FOUND_ROWS would seem useful should simply be solved by other mechanisms than LIMIT/OFFSET. E.g., a phone book should be paginated by letter (both in terms of UX and in terms of index use), not by record number. Discussions are increasingly infinite-scroll ordered by date (again allowing index use), not by paginated by post number. And so on.
There are other options for you to benchmark:
1.) A window function will return the actual size directly (tested in MariaDB):
SELECT
`mytable`.*,
COUNT(*) OVER() AS `total_count`
FROM `mytable`
ORDER BY `mycol`
LIMIT 10, 20
2.) Thinking out of the box, most of the time users don't need to know the EXACT size of the table, an approximate is often good enough.
SELECT `TABLE_ROWS` AS `rows_approx`
FROM `INFORMATION_SCHEMA`.`TABLES`
WHERE `TABLE_SCHEMA` = DATABASE()
AND `TABLE_TYPE` = "BASE TABLE"
AND `TABLE_NAME` = ?
'Programing' 카테고리의 다른 글
pylab과 pyplot의 차이점은 무엇입니까? (0) | 2020.05.27 |
---|---|
ggplot2 구문이 합리적 일 때 "전역 변수에 대한 가시적 바인딩 없음"메모를 어떻게 R CMD 검사를 처리 할 수 있습니까? (0) | 2020.05.27 |
JavaScript를 사용하여 파일을 읽고 쓰는 방법? (0) | 2020.05.27 |
Expires와 Cache-Control 헤더의 차이점은 무엇입니까? (0) | 2020.05.27 |
C ++의 내부 typedef-좋은 스타일 또는 나쁜 스타일? (0) | 2020.05.27 |