代码之家  ›  专栏  ›  技术社区  ›  planetp

执行语句是否总是占用结果集的内存?

  •  9
  • planetp  · 技术社区  · 14 年前

    一位同事告诉我,执行SQL语句总是会将数据放入数据库服务器的RAM/swap中。因此,选择较大的结果集是不现实的。

    我以为这样的密码

    my $sth = $dbh->prepare('SELECT million_rows FROM table');
    while (my @data = $sth->fetchrow) {
        # process the row
    }
    

    逐行检索结果集,而不将其加载到RAM。 但我在DBI或MySQL文档中找不到对此的任何引用。如何真正创建和检索结果集?对于简单的选择和联接,它是否工作相同?

    4 回复  |  直到 14 年前
        1
  •  6
  •   Jamie McCarthy    14 年前

    你的同事是对的。

    默认情况下,Perl模块dbd::mysql使用mysql_store_result,它确实读取所有选择的数据并将其缓存到RAM中。除非更改该默认值,否则当您在DBI中逐行获取数据时,它只是从内存缓冲区中读取数据。

    这通常是您想要的,除非您有非常大的结果集。否则,在从mysqld中获取最后一个数据之前,它必须将该数据保持就绪,我的理解是,它会导致写入相同行(块)时出现块。桌子?).

    记住,现代机器有很多RAM。一百万行结果集通常不是什么大问题。即使每行的大小都相当大,只有1 GB的RAM加上开销。

    如果要处理数百万行的blob,可能需要mysql使用结果,也可能需要以块的形式选择这些行,并逐步使用 LIMIT x,y .

    参见mysql_use_result和mysql_store_result in perldoc DBD::mysql 详情。

        2
  •  6
  •   Quassnoi    14 年前

    这不是真的(如果我们谈论的是数据库服务器本身,而不是客户机层)。

    MySQL 可以缓冲整个结果集,但这不一定要完成,如果完成,也不一定要在 RAM .

    如果使用内联视图,则会缓冲结果集。( SELECT FROM (SELECT …) ,查询需要排序(如 using filesort 或者计划需要创建一个临时表(如 using temporary 在查询计划中)。

    即使 临时使用 , MySQL 仅当表的大小不超过 tmp_table . 当表超过此限制时,它将从 memory 进入之内 MyISAM 存储在磁盘上。

    不过,你可以明确指示 MySQL 通过附加 SQL_BUFFER_RESULT 最外面的指示 SELECT .

    docs 更多细节。

        3
  •  3
  •   Unreason    14 年前

    不,这不是它的工作原理。

    数据库不会在RAM/SWAP中保存行。

    但是,它会尝试,并且MySQL会在这里努力,尽可能多地缓存(索引、结果等)。MySQL配置为不同类型的缓存(不同类型的存储引擎)提供可用内存缓冲区的值-不应允许交换此缓存。

    测试它
    底线——只使用客户机测试应该很容易(我不知道Perl的DBI,但我怀疑它可能正在做一些迫使MySQL加载所有准备工作的事情)。总之…测试它:

    如果你真的在 SELECT SQL_NO_CACHE million_rows FROM table 然后从数百万中只取几行。 然后你应该把表现和 SELECT SQL_NO_CACHE only_fetched_rows FROM table 看看价格如何。 如果你的表现相当(而且很快),那么我相信你可以称之为你同事的虚张声势。

    另外,如果您启用实际发布到MySQL的语句日志,并为我们提供一个副本,那么我们(非Perl人员)可以对MySQL将做什么给出更明确的答案。

        4
  •  1
  •   ysth    14 年前

    我不太熟悉这一点,但在我看来dbd::mysql可以预先获取所有内容,或者仅在需要时根据mysql_use_result属性获取所有内容。请参阅dbd::mysql和mysql文档。