• mysql中关于SQL_CALC_FOUND_ROWS的使用与否


    最近在代码中发现了这个mysql关键字 SQL_CALC_FOUND_ROWS

    代码中是这么写的:

    $dbProxy = self::getDBProxy();
    $sql = "SELECT SQL_CALC_FOUND_ROWS * FROM rl_item_img_relation WHERE img_id=$id  limit 0,100 ";
    $ret = $dbProxy->rs2array($sql);
    $count = $dbProxy->rs2foundrows();

    用处自然是无需在写一个count(img_id) ,省了一个方法,那么性能如何呢?

    这里找到老外的一篇文章(http://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/),自己动手试下,眼见为实嘛!

    mysql> CREATE TABLE `count_test` (
        ->   `a` int(10) NOT NULL auto_increment,
        ->   `b` int(10) NOT NULL,
        ->   `c` int(10) NOT NULL,
        ->   `d` varchar(32) NOT NULL,
        ->   PRIMARY KEY  (`a`),
        ->   KEY `bc` (`b`,`c`)
        -> ) ENGINE=MyISAM;
    Query OK, 0 rows affected (0.01 sec)
    <?php
    mysql_connect("127.0.0.1", "root");
    mysql_select_db("test");
    for ($i = 0; $i < 10000000; $i++) {
        $b = $i % 1000;
        mysql_query("INSERT INTO count_test SET b=$b, c=ROUND(RAND()*10), d=MD5($i)");
    }

    我这里先是导入了大约124万,下面来查询下:

    mysql> SELECT SQL_NO_CACHE * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +-------+-----+---+----------------------------------+
    | a     | b   | c | d                                |
    +-------+-----+---+----------------------------------+
    | 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
    +-------+-----+---+----------------------------------+
    1 row in set (0.01 sec)
    
    mysql> SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +----------+
    | count(*) |
    +----------+
    |     1247 |
    +----------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SQL_NO_CACHE   SQL_CALC_FOUND_ROWS  * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +-------+-----+---+----------------------------------+
    | a     | b   | c | d                                |
    +-------+-----+---+----------------------------------+
    | 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
    +-------+-----+---+----------------------------------+
    1 row in set (0.01 sec)

    两条分开的语句和合并一起的貌似没有什么差距。继续导入数据到千万级数据看下:

    mysql> SELECT SQL_NO_CACHE   SQL_CALC_FOUND_ROWS  * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +-------+-----+---+----------------------------------+
    | a     | b   | c | d                                |
    +-------+-----+---+----------------------------------+
    | 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
    +-------+-----+---+----------------------------------+
    1 row in set (45.14 sec)
    
    mysql> SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +----------+
    | count(*) |
    +----------+
    |    11247 |
    +----------+
    1 row in set (0.01 sec)
    
    mysql> SELECT SQL_NO_CACHE * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +-------+-----+---+----------------------------------+
    | a     | b   | c | d                                |
    +-------+-----+---+----------------------------------+
    | 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
    +-------+-----+---+----------------------------------+
    1 row in set (0.00 sec)

    差距出来了,为什么?

    看看sql语句的explain

    mysql> explain SELECT SQL_NO_CACHE   SQL_CALC_FOUND_ROWS  * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    | id | select_type | table      | type | possible_keys | key  | key_len | ref   | rows  | Extra       |
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    |  1 | SIMPLE      | count_test | ref  | bc            | bc   | 4       | const | 11431 | Using where |
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain   SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    | id | select_type | table      | type | possible_keys | key  | key_len | ref   | rows  | Extra       |
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    |  1 | SIMPLE      | count_test | ref  | bc            | bc   | 4       | const | 11431 | Using index |
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain SELECT SQL_NO_CACHE * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    | id | select_type | table      | type | possible_keys | key  | key_len | ref   | rows  | Extra       |
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    |  1 | SIMPLE      | count_test | ref  | bc            | bc   | 4       | const | 11431 | Using where |
    +----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
    1 row in set (0.00 sec)

    原博只是比对了后两条语句,没有进行第一条语句的比较,直接得出了结论,但是如果加上第一条语句的话,还是无法解释上述的查询的时间差距,原博得出这个结论是片面的。

    根据mysql 官方手册(http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_found-rows)描述:

         If you are using SELECT SQL_CALC_FOUND_ROWS, MySQL must calculate how many rows are in the full result set. 
    However, this is faster than running the query again without LIMIT, because the result set need not be sent 
    to the client.
    
       SQL_CALC_FOUND_ROWS and FOUND_ROWS() can be useful in situations when you want to restrict the number of rows
     that a query returns, but also determine the number of rows in the full result set without running the query again.
     An example is a Web script that presents a paged display containing links to the pages that show other sections of 
    a search result. Using FOUND_ROWS() enables you to determine how many other pages are needed for the rest of the 
    result.

    按照手册说法,SQL_CALC_FOUND_ROWS 和 FOUND_ROWS()是被推荐使用的,至少比再查询一次快。就像原博评论里说的,我们没有理由不相信官方手册啊!

  • 相关阅读:
    Oracle创建表空间用户等
    centos7安装neo4j
    Linux 介绍和命令超详细
    Go 变量声明
    Manjaro 安装 & 配置
    Go Golang安装及环境变量配置
    python3集合与常用操作
    正则以及re库的使用
    Requests 库安装
    数据库-数据库管理系统-数据库系统
  • 原文地址:https://www.cnblogs.com/gaoj87/p/4057036.html
Copyright © 2020-2023  润新知