精华内容
下载资源
问答
  • 数据库中Count的使用

    2015-03-16 15:55:02
    数据库中Count的使用: select count(*) as 人数,count(phone) as 有电话的人数 from student 其中:count(*) 表示student表中所有记录的个数 count(phone)表示student表中phone不空null的记录个数
  • COUNT的几种用法 COUNT(expr),返回select语句检索行expr的值不为NULL的数量,结果是一个BIGINT值 如果没有命中任何记录,返回0 COUNT(*)统计时会包含值为NULL的行数 COUNT(*)的优化 MyISAM:一个简单得...

    COUNT的几种用法

    1. COUNT(expr),返回select语句检索行中expr的值不为NULL的数量,结果是一个BIGINT值
    2. 如果没有命中任何记录,返回0
    3. COUNT(*)统计时会包含值为NULL的行数

    COUNT(*)的优化

    • MyISAM:一个简单得优化,它把表的总行数单独记录下来,如果从一张表中使用COUNT(*)进行查询,就可以直接返回这个记录下来的数值就可以了
    • InnoDB:应为innodb大部分操作是行级锁,所以不能用上面的缓存操作。所以InnoDB进行查询行数时,只是为了统计行数,会在扫表的过程中,选择一个成本较低的索引进行,大大节省空间。Mysql会选择最小的非聚簇索引来扫表。

    COUNT(1)和COUNT(*)区别

    • 对与COUNT(1)和COUNT(*)来说,mysql的优化是完全一样的,根本不存在谁比谁快
    • 建议使用COUNT(*),因为这个是sql92中定义的标准统计行数的语法。

    COUNT(字段)

    • 查询比较简单粗暴,就是进行全表扫描,判断指定字段是否为NULL,不是NULL则累加。
    • 多了一个判断NULL的操作,所以效率会比COUNT(*)慢
    展开全文
  • 数据库中COUNT(*)执行原理

    千次阅读 2019-12-24 22:40:16
    在 MySQL 的使用规范,我们一般使用事务引擎 InnoDB 作为(一般业务)表的存储引擎,在此前提下,COUNT()操作的时间复杂度为 O(N),其中 N 为表的行数。 而 MyISAM 表可以快速取到表的行数。这些实践经验的背后是...

    来源:https://url.cn/5zSuErM

    “SELECT COUNT() FROM t” 是个再常见不过的 SQL 需求了。在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表的存储引擎,在此前提下,COUNT()操作的时间复杂度为 O(N),其中 N 为表的行数。

    而 MyISAM 表中可以快速取到表的行数。这些实践经验的背后是怎样的机制,以及为什么需要/可以是这样,就是此文想要探讨的。

    先来看一下概况: MySQL COUNT(*) 在 2 种存储引擎中的部分问题:

    下面就带着这些问题,以 InnoDB 存储引擎为主来进行讨论。

    一、InnoDB 全表 COUNT(*)

    执行过程是怎样的?

    ①、如何计算 count?影响 count 结果的因素有哪些?

    ②、count 值存在哪里?涉及的数据结构是怎样的?

    ③、为什么 InnoDB 只能通过扫表来实现 count(*)?(见本文最后的问题)

    ④、全表COUNT(*)作为 table scan 类型操作的一个 case,有什么风险?

    ⑤、COUNT()操作是否会像“SELECT ”一样可能读取大字段涉及的溢出页?

    1、执行框架 – 循环: 读取 计数

    1.1 基本结论

    全表扫描,一个循环解决问题。

    循环内: 先读取一行,再决定该行是否计入 count。

    循环内是一行一行进行计数处理的。

    1.2 说明

    简单 SELELCT-SQL 的执行框架,类比 INSERT INTO … SELECT 是同样的过程。

    下面会逐步细化如何读取与计数 ( count ) 。

    2、执行过程

    ①、COUNT(*) 前置流程: 从 Client 端发 SQL 语句,到 MySQL-Server 端执行 SELECT 之前,为后面的一些阐述做一铺垫。

    ②、COUNT(*) 流程: 简要给出代码层面的流程框架及 2 个核心步骤的重点调用栈部分。

    ③、读取一行: 可见性及 rowsearchmvcc 函数,介绍可见性如何影响 COUNT(*) 结果。

    ④、计数一行: Evaluatejoinrecord 与列是否为空,介绍计数过程如何影响 COUNT(*) 结果。

    如果希望直接看如何进行 COUNT(*),那么也可以忽略 (1),而直接跳到 (2) 开始看。

    2.1 COUNT(*) 前置流程回忆 – 从 Client 端发 SQL 到 sub_select 函数

    为了使看到的调用过程不太突兀,我们还是先回忆一下如何执行到 sub_select 函数这来的:

    ①、MySQL-Client 端发送 SQL 语句,根据 MySQL 通信协议封包发送。

    ②、Mysql-Server 端接收数据包,由协议解析出 command 类型 ( QUERY ) 及 SQL 语句 ( 字符串 ) 。

    ③、SQL 语句经过解析器解析输出为 JOIN 类的对象,用于结构化地表达该 SQL 语句。PS: 这里的 JOIN 结构,不仅仅是纯语法结构,而是已经进行了语义处理,粗略地说,汇总了表的列表 ( tablelist )、目标列的列表 ( targetlist )、WHERE 条件、子查询等语法结构。在全表 COUNT( )-case 中,tablelist = [表“t”(别名也是“t”)],targetlist = [目标列对象(列名为“COUNT( )”)],当然这里没有 WHERE 条件、子查询等结构。

    ④、JOIN 对象有 2 个重要的方法: JOIN::optimize(), JOIN::exec(),分别用于进行查询语句的优化 和 查询语句的执行。

    join->optimize(),优化阶段 (稍后 myisam 下全表 count(*) 操作会涉及这里的一点内容)。

    join->exec(),执行阶段 ( 重点 ),包含了 InnoDB 下全表count(*) 操作的执行流程。

    ⑤、join->exec() 经过若干调用,将调用到 sub_select 函数来执行简单 SQL,包括 COUNT(*) 。

    ⑥、 END of sub_select 。

    2.2 COUNT( * ) 流程 ( 于 sub_select 函数中 )

    上层的流程与代码是比较简单的,集中在 sub_select 函数中,其中 2 类函数分别对应于前面”执行框架”部分所述的 2 个步骤 – 读取、计数。先给出结论如下:

    ①、读取一行:从相对顶层的 subselect 函数经过一番调用,最终所有分支将调用到 rowsearchmvcc 函数中,该函数就是用于从 InnoDB 存储引擎所存储的 B -tree 结构中读取一行到内存中的一个 buf (uchar ) 中,待后续处理使用。这里会涉及行锁的获取、MVCC 及行可见性的问题。当然对 于 SELECT COUNT() 这类快照读而言,只会涉及 MVCC 及其可见性,而不涉及行锁。详情可跳至“可见性与 rowsearch_mvcc 函数”部分。

    ②、计数一行: 代码层面,将会在 evaluatejoinrecord 函数中对所读取的行进行评估,看其是否应当计入 count 中 ( 即是否要 count )。简单来说,COUNT(arg) 本身为 MySQL 的函数操作,对于一行来说,若括号内的参数 arg ( 某列或整行 ) 的值若不是 NULL,则 count ,否则对该行不予计数。详情可跳至“ Evaluatejoinrecord 与列是否为空”部分。

    这两个阶段对 COUNT(*)结果的影响如下: (两层过滤)

    SQL 层流程框架相关代码摘要如下:

    1210 enum_nested_loop_state
     
    1211 sub_select(JOIN *join, QEP_TAB *const qep_tab,bool end_of_records)
    1212 {
    1213   DBUG_ENTER("sub_select");
     
    ... ... // 此处省略1000字
     
    1265   while (rc == NESTED_LOOP_OK && join->return_tab >= qep_tab_idx)
    1266   {
    1267     int error;
    // 第一步,从存储引擎中获取一行;
    1268     if (in_first_read)
    1269     {
    1270       in_first_read= false;
    // 第一步,首次读取,扫描第一个满足条件的记录;
    // 初始化cursor,从”头”扫描到某个位置
    // 类似: SELECT id FROM t LIMIT 1;
    1271       error= (*qep_tab->read_first_record)(qep_tab);
    1272     }
    1273     else
    // 第一步,后续读取,在前次扫描的位置上继续遍历,找到一个满足条件的记录;
    // 类似: SELECT id FROM t WHERE id > $last_id LIMIT 1;
    1274       error= info->read_record(info);
     
    ... ... // 此处省略1000字
     
    // 第二步,处理刚刚取出的一行
    1291       rc= evaluate_join_record(join, qep_tab);
    ... ... // 此处省略1000字
    1303   DBUG_RETURN(rc);
    1304 }

    Q:代码层面,第一步骤(读取一行)有 2 个分支,为什么?

    A:从 InnoDB 接口层面考虑,分为 “读第一行” 和 “读下一行”,是 2 个不同的执行过程,读第一行需要找到一个 ( cursor ) 位置并做一些初始化工作让后续的过程可递归。

    正如我们如果用脚本/程序来进行逐行的扫表操作,实现上就会涉及下面 2 个 SQL:

    // SELECT id FROM t LIMIT 1; OR SELECT MIN(id)-1 FROM t; -> $last_id
     
    // SELECT id FROM t WHERE id > $last_id LIMIT 1;

    具体涉及到此例的代码,SQL 层到存储引擎层的调用关系,读取阶段的调用栈如下:(供参考)

    sub_select 函数中从 SQL 层到 InnoDB 层的函数调用关系:(同颜色、同缩进 表示同一层)

    Ø  (*qep_tab->read_first_record) ()
     
    | -- > join_read_first(tab)
        | -- > tab->read_record.read_record=join_read_next;
        | -- > table->file->ha_index_init()
            | -- > handler::ha_index_init(uint idx, bool sorted)
                | -- > ha_innobase::index_init()
        | -- > table->file->ha_index_first()
            | -- > handler::ha_index_first(uint idx, bool sorted)
                | -- > ha_innobase::index_first()
                    | -- > ha_innobase::index_read()
                        | -- > row_search_mvcc()
                        初始化cursor并将其放到一个有效的初始位置上;
     
    Ø  info->read_record (info)
     
    | -- > join_read_next(info)
        | -- > info->table->file->ha_index_next(info->record))
            | -- > handler::ha_index_next(uchar * buf)
                | -- > ha_innobase::index_next(uchar * buf)
                    | -- > general_fetch(buf, ROW_SEL_NEXT, 0)
                        | -- > row_search_mvcc()
                            “向前”移动一次cursor;

    我们可以看到,无论是哪一个分支的读取,最终都殊途同归于 rowsearchmvcc 函数。

    以上是对 LOOP 中的代码做一些简要的说明,下面来看 rowsearchmvcc 与 evaluatejoinrecord 如何输出最终的 count 结果。

    2.3 行可见性及 rowsearchmvcc 函数

    这里我们主要通过一组 case 和几个问题来看行可见性对 COUNT(*) 的影响。

    Q:对于“SELECT COUNT(*) FROM t”或者“SELECT MIN(id) FROM t”操作,第一次的读行操作读到的是表 t 中 ( B 树最左叶节点 page 内 ) 的最小记录吗?( ha_index_first 为何也调用 row_search_mvcc 来获取最小 key 值?)

    A:不一定。即使是 MIN(id) 也不一定就读取的是 id 最小的那一行,因为也同样有行可见性的问题,实际上 indexread 取到的是 当前事务内语句可见的最小 index 记录。这也反映了前面提到的 joinreadfirst 与 joinreadnext “殊途同归”到 rowsearch_mvcc 是理所应当的。

    Q:针对图中最后一问,如果事务 X 是 RU ( Read-Uncommitted ) 隔离级别,且 C-Insert ( 100 ) 的完成是在 X-count() 执行过程中 ( 仅扫描到 5 或 10 这条记录 ) 完成的,那么 X-count() 在事务 C-Insert ( 100 ) 完成后,能否在之后的读取过程中看到 100 这条记录呢?

    A:MySQL 采取”读到什么就是什么”的策略,即 X-count(*) 在后面可以读到 100 这条记录。

    2.4 evaluatejoinrecord 与列是否为空

    Q:某一行如何计入 count?

    A:两种情况会将所读的行计入 count:

    ①、如果 COUNT 函数中的参数是某列,则会判断所读行中该列定义是否 Nullable 以及该列的值是否为 NULL;若两者均为是,则不会计入 count,否则将计入 count。

       e.g. SELECT COUNT(col_name) FROM t
       col_name 可以是主键、唯一键、非唯一键、非索引字段

    ②、 如果 COUNT 中带有 * ,则会判断这部分的整行是否为 NULL,如果判断参数为 NULL,则忽略该行,否则 count 。

    e.g-1. SELECT COUNT(*) FROM t
    e.g-2. SELECT COUNT(B.*) FROM A LEFT JOIN B ON A.id = B.id

    Q:特别地,对于 SELECT COUNT(id) FROM t,其中 id 字段是表 t 的主键,则如何?

    A:效果上等价于 COUNT()。因为无论是 COUNT(),还是 COUNT ( pk_col ) 都是因为有主键从而充分断定索取数据不为 NULL,这类 COUNT 表达式可以用于获取当前可见的表行数。

    Q:用户层面对 InnoDB COUNT(*) 的优化操作问题

    A:这个问题是业界熟悉的一个问题,扫描非空唯一键可得到表行数,但所涉及的字节数可能会少很多(在表的行长与主键、唯一键的长度相差较多时),相对的 IO 代价小很多。

    相关调用栈参考如下:

    参考一:

    evaluate_join_record()
     
    | -- > rc= (*qep_tab->next_select)(join, qep_tab 1, 0);
        | -- > end_send_group(...)
            | -- > init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx 1]))
                | -- > (*func_ptr)->reset_and_add()
                    | -- > Item_sum::aggregator_clear()
                    | -- > Item_sum::aggregator_add()
            | -- > update_sum_func(Item_sum **func_ptr)
                | -- > (*func_ptr)->add()
                    | -- > Item_sum::aggregator_add()

    参考二:

    (Item_sum::aggregator_add)
     
    ((Item_sum *) (*func_ptr))->aggregator_add()
     
    | -- > (Item_sum *)this->aggr->add()
        | -- > ((Aggregator_simple *) aggr)->item_sum->add()
            | -- > if (! aggr->arg_is_null(false))
            | ------ > ((Item_sum_count *)aggr->item_sum)->count  ;

    二、数据结构:

    Q:count 值存储在哪个内存变量里?

    A:SQL 解析后,存储于表达 COUNT() 这一项中,((Itemsumcount)item_sum)->count

    如下图所示回顾我们之前“COUNT(*)前置流程”部分提到的 JOIN 结构。

    即 SQL 解析器为每个 SQL 语句进行结构化,将其放在一个 JOIN 对象 ( join ) 中来表达。在该对象中创建并填充了一个列表 resultfieldlist 用于存放结果列,列表中每个元素则是一个结果列的 ( Itemresultfield* ) 对象 ( 指针 ) 。

    在 COUNT()-case 中,结果列列表只包含一个元素,( Itemsumcount: public Itemresultfield ) 类型对象 ( name = “COUNT()”),其中该类所特有的成员变量 count即为所求。

    三、MyISAM 全表 COUNT(*)

    由于 MyISAM 引擎并不常用于实际业务中,仅做简要描述如下:

    MyISAM-COUNT(*) 操作是 O(1) 时间复杂度的操作。

    每张 MyISAM 表中存放了一个 meta 信息-count 值,在内存中与文件中各有一份,内存中的 count 变量值通过读取文件中的 count 值来进行初始化。

    SELECT COUNT(*) FROM t 会直接读取内存中的表 t 对应的 count 变量值。

    内存中的 count 值与文件中的 count 值由写操作来进行更新,其一致性由表级锁来保证。

    表级锁保证的写入串行化使得,同一时刻所有用户线程的读操作要么被锁,要么只会看到一种数据状态。

    四、几个问题

    Q:MyISAM 与 InnoDB 在 COUNT(*) 操作的执行过程在哪里开始分道扬镳?

    共性:共性存在于 SQL 层,即 SQL 解析之后的数据结构是一致的,count 变量都是存在于作为结果列的 Itemsumcount 类型对象中;返回给客户端的过程也类似 – 对该 count 变量进行赋值并经由 MySQL 通信协议返回给客户端。

    区别:InnoDB 的 count 值计算是在 SQL 执行阶段进行的;而 MyISAM 表本身在内存中有一份包含了表 row_count 值的 meta 信息,在 SQL 优化阶段通过存储引擎的标记给优化器一个 hint,表明该表所用的存储引擎保存了精确行数,可以直接获取到,无需再进入执行器。

    Q:InnoDB 中为何无法向 MyISAM 一样维护住一个 row_count 变量?

    A:从 MVCC 机制与行可见性问题中可得到原因,每个事务所看到的行可能是不一样的,其 count(*) 结果也可能是不同的;反过来看,则是 MySQL-Server 端无法在同一时刻对所有用户线程提供一个统一的读视图,也就无法提供一个统一的 count 值。

    PS: 对于多个访问 MySQL 的用户线程 ( COUNT(*) ) 而言,决定它们各自的结果的因素有几个:

    ①、一组事务执行前的数据状态(初始数据状态)。

    ②、有时间重叠的事务们的执行序列 (操作时序,事务理论表明 并发事务操作的可串行化是正确性的必要条件)。

    ③、事务们各自的隔离级别(每个操作的输入)。

    其中 1、2 对于 Server 而言都是全局或者说可控的,只有 3 是每个用户线程中事务所独有的属性,这是 Server 端不可控的因素,因此 Server 端也就对每个 COUNT(*) 结果不可控了。

    Q:InnoDB-COUNT(*) 属 table scan 操作,是否会将现有 Buffer Pool 中其它用户线程所需热点页从 LRU-list 中挤占掉,从而其它用户线程还需从磁盘 load 一次,突然加重 IO 消耗,可能对现有请求造成阻塞?

    A:MySQL 有这样的优化策略,将扫表操作所 load 的 page 放在 LRU-list 的 oung/old 的交界处 ( LRU 尾部约 3/8 处 )。这样用户线程所需的热点页仍然在 LRU-list-young 区域,而扫表操作不断 load 的页则会不断冲刷 old 区域的页,这部分的页本身就是被认为非热点的页,因此也相对符合逻辑。

    PS: 个人认为还有一种类似的优化思路,是限定扫描操作所使用的 Buffer Pool 的大小为 O(1) 级别,但这样做需要付出额外的内存管理成本。

    Q:InnoDB-COUNT() 是否会像 SELECT FROM t 那样读取存储大字段的溢出页(如果存在)?

    A:否。因为 InnoDB-COUNT(*) 只需要数行数,而每一行的主键肯定不是 NULL,因此只需要读主键索引页内的行数据,而无需读取额外的溢出页。

    关注公众号-小罗技术笔记

    展开全文
  • 使用HibernateTemplate对数据库中的数据求count的时候

    在使用HibernateTemplate对数据库中的数据求count的时候出现的异常,我的dao的代码和异常代码如下:

    先是dao的代码:

    	public int findCurrentAllCount()throws Exception{
    		
    		final String sql = "select count(*) from lbs.area_log_current"; //当前区域总人数
    		
    		return super.getHibernateTemplate().execute(new HibernateCallback() {
    			@Override
    			public Object doInHibernate(Session session)
    					throws HibernateException, SQLException {
    				// TODO Auto-generated method stub
    				Query query = session.createSQLQuery(sql);
    				Object obj = query.uniqueResult();
    				return obj != null ? ((Long)obj).intValue() : 0; //这里的obj的数据类型是一个BigInteger类型,不能转换为Long,否则会报出如下的异常
    			}
    		});
    	}


     

    这是异常代码

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:659)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.framework.util.EncodeFilter.doFilter(EncodeFilter.java:62)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    	at java.lang.Thread.run(Thread.java:722)
    Caused by: java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long
    	at com.wafersystems.lbs.dao.impl.location.AreaLogCurrentDAO$1.doInHibernate(AreaLogCurrentDAO.java:152)
    	at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
    	at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
    	at com.wafersystems.lbs.dao.impl.location.AreaLogCurrentDAO.findCurrentAllCount(AreaLogCurrentDAO.java:145)
    	at com.wafersystems.lbs.service.impl.location.AreaLogCurrentService.findAreaLogCurrentCount(AreaLogCurrentService.java:48)
    	at com.wafersystems.lbs.action.location.AreaLogCurrentAction.showAreaLogCurrentList(AreaLogCurrentAction.java:38)
    	at com.wafersystems.lbs.action.location.AreaLogCurrentAction$$FastClassByCGLIB$$bd7ac7d0.invoke(<generated>)
    	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    	at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:692)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:50)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
    	at com.wafersystems.lbs.utils.AopAdvice.aroundAdvice(AopAdvice.java:126)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:601)
    	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:622)
    	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:611)
    	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
    	at com.wafersystems.lbs.action.location.AreaLogCurrentAction$$EnhancerByCGLIB$$b03baa93.showAreaLogCurrentList(<generated>)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:601)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:710)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:167)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:414)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:402)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
    	... 25 more


    后来将代码中

    return obj != null ?  ((Long) obj).intValue() : 0;   改为了

    return obj != null ? ((BigInteger) obj).intValue() : 0; 后来一切正常

    展开全文
  • 1、COUNT有几种用法? 2、COUNT(字段名)和COUNT(*)查询结果有什么不同?...5、为什么《阿里巴巴Java开发手册》建议使用COUNT(*) 6、MySQLMyISAM引擎对COUNT(*)做了哪些优化? 7、MySQLInnoDB引擎对COUNT(*...

    1、COUNT有几种用法?

    2、COUNT(字段名)和COUNT(*)的查询结果有什么不同?

    3、COUNT(1)和COUNT(*)之间有什么不同?

    4、COUNT(1)和COUNT(*)之间的效率哪个更高?

    5、为什么《阿里巴巴Java开发手册》建议使用COUNT(*)

    6、MySQL的MyISAM引擎对COUNT(*)做了哪些优化?

    7、MySQL的InnoDB引擎对COUNT(*)做了哪些优化?

    8、上面提到的MySQL对COUNT(*)做的优化,有一个关键的前提是什么?

    9、SELECT COUNT(*) 的时候,加不加where条件有差别吗?

    10、COUNT(*)、COUNT(1)和COUNT(字段名)的执行过程是怎样的?

     

    以上10道题,如果您可以全部准确无误的回答的话,那说明你真的很了解COUNT函数了,如果有哪些知识点是不了解的,那么本文正好可以帮你答疑解惑。

     

     

    1.认识COUNT

    关于COUNT函数,在MySQL官网中有详细介绍:

     

    简单翻译一下:

    1、COUNT(expr) ,返回SELECT语句检索的行中expr的值不为NULL的数量。结果是一个BIGINT值。

    2、如果查询结果没有命中任何记录,则返回0

    3、但是,值得注意的是,COUNT(*)的统计结果中,会包含值为NULL的行数。

     

    即以下表记录:

    
     
    create table #bla(id int,id2 int)
    insert #bla values(null,null)
    insert #bla values(1,null)
    insert #bla values(null,1)
    insert #bla values(1,null)
    insert #bla values(null,1)
    insert #bla values(1,null)
    insert #bla values(null,null)

     

    使用语句count(*),count(id),count(id2)查询结果如下:

    
     
    select count(*),count(id),count(id2)
    from #bla
    results 7 3 2

     

    除了COUNT(id)和COUNT(*)以外,还可以使用COUNT(常量)(如COUNT(1))来统计行数,那么这三条SQL语句有什么区别呢?到底哪种效率更高呢?为什么《阿里巴巴Java开发手册》中强制要求不让使用 COUNT(列名)或 COUNT(常量)来替代 COUNT(*)呢?

     

     

     

    2.COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别

     

    前面我们提到过COUNT(expr)用于做行数统计,统计的是expr不为NULL的行数,那么COUNT(列名)、 COUNT(常量) 和 COUNT(*)这三种语法中,expr分别是列名、 常量 和 *。

     

    那么列名、 常量 和 *这三个条件中,常量 是一个固定值,肯定不为NULL。*可以理解为查询整行,所以肯定也不为NULL,那么就只有列名的查询结果有可能是NULL了。

     

    所以, COUNT(常量) 和 COUNT(*)表示的是直接查询符合条件的数据库表的行数。而COUNT(列名)表示的是查询符合条件的列的值不为NULL的行数。

     

    除了查询得到结果集有区别之外,COUNT(*)相比COUNT(常量) 和 COUNT(列名)来讲,COUNT(*)是SQL92定义的标准统计行数的语法,因为他是标准语法,所以MySQL数据库对他进行过很多优化。

     

    SQL92,是数据库的一个ANSI/ISO标准。它定义了一种语言(SQL)以及数据库的行为(事务、隔离级别等)。

     

     

    3.COUNT(*)的优化

     

    前面提到了COUNT(*)是SQL92定义的标准统计行数的语法,所以MySQL数据库对他进行过很多优化。那么,具体都做过哪些事情呢?

     

    这里的介绍要区分不同的执行引擎。MySQL中比较常用的执行引擎就是InnoDB和MyISAM。

     

    MyISAM和InnoDB有很多区别,其中有一个关键的区别和我们接下来要介绍的COUNT(*)有关,那就是MyISAM不支持事务,MyISAM中的锁是表级锁;而InnoDB支持事务,并且支持行级锁。

     

    因为MyISAM的锁是表级锁,所以同一张表上面的操作需要串行进行,所以,MyISAM做了一个简单的优化,那就是它可以把表的总行数单独记录下来,如果从一张表中使用COUNT(*)进行查询的时候,可以直接返回这个记录下来的数值就可以了,当然,前提是不能有where条件。

     

    MyISAM之所以可以把表中的总行数记录下来供COUNT(*)查询使用,那是因为MyISAM数据库是表级锁,不会有并发的数据库行数修改,所以查询得到的行数是准确的。

     

    但是,对于InnoDB来说,就不能做这种缓存操作了,因为InnoDB支持事务,其中大部分操作都是行级锁,所以可能表的行数可能会被并发修改,那么缓存记录下来的总行数就不准确了。

     

    但是,InnoDB还是针对COUNT(*)语句做了些优化的。

     

    在InnoDB中,使用COUNT(*)查询行数的时候,不可避免的要进行扫表了,那么,就可以在扫表过程中下功夫来优化效率了。

     

    从MySQL 8.0.13开始,针对InnoDB的SELECT COUNT(*) FROM tbl_name语句,确实在扫表的过程中做了一些优化。前提是查询语句中不包含WHERE或GROUP BY等条件。

     

    我们知道,COUNT(*)的目的只是为了统计总行数,所以,他根本不关心自己查到的具体值,所以,他如果能够在扫表的过程中,选择一个成本较低的索引进行的话,那就可以大大节省时间。

     

    我们知道,InnoDB中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值。

     

    所以,相比之下,非聚簇索引要比聚簇索引小很多,所以MySQL会优先选择最小的非聚簇索引来扫表。所以,当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。

     

    至此,我们介绍完了MySQL数据库对于COUNT(*)的优化,这些优化的前提都是查询语句中不包含WHERE以及GROUP BY条件。

     

     

     

    4.COUNT(*)和COUNT(1)

     

     

    介绍完了COUNT(*),接下来看看COUNT(1),对于,这二者到底有没有区别,网上的说法众说纷纭。

     

    有的说COUNT(*)执行时会转换成COUNT(1),所以COUNT(1)少了转换步骤,所以更快。

     

    还有的说,因为MySQL针对COUNT(*)做了特殊优化,所以COUNT(*)更快。

     

    那么,到底哪种说法是对的呢?看下MySQL官方文档是怎么说的:

    InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

     

    画重点:same way , no performance difference。所以,对于COUNT(1)和COUNT(*),MySQL的优化是完全一样的,根本不存在谁比谁快!

     

    那既然COUNT(*)和COUNT(1)一样,建议用哪个呢?

     

    建议使用COUNT(*)!因为这个是SQL92定义的标准统计行数的语法,而且本文只是基于MySQL做了分析,关于Oracle中的这个问题,也是众说纷纭的呢。

     

    5.COUNT(字段)

     

    最后,就是我们一直还没提到的COUNT(字段),他的查询就比较简单粗暴了,就是进行全表扫描,然后判断指定字段的值是不是为NULL,不为NULL则累加。

     

    相比COUNT(*),COUNT(字段)多了一个步骤就是判断所查询的字段是否为NULL,所以他的性能要比COUNT(*)慢。

     

     

    6.总结

     

    本文介绍了COUNT函数的用法,主要用于统计表行数。主要用法有COUNT(*)、COUNT(字段)和COUNT(1)。

     

    因为COUNT(*)是SQL92定义的标准统计行数的语法,所以MySQL对他进行了很多优化,MyISAM中会直接把表的总行数单独记录下来供COUNT(*)查询,而InnoDB则会在扫表的时候选择最小的索引来降低成本。当然,这些优化的前提都是没有进行where和group的条件查询。

     

    在InnoDB中COUNT(*)和COUNT(1)实现上没有区别,而且效率一样,但是COUNT(字段)需要进行字段的非NULL判断,所以效率会低一些。

     

    因为COUNT(*)是SQL92定义的标准统计行数的语法,并且效率高,所以请直接使用COUNT(*)查询表的行数!

    展开全文
  • 数据库SELECT COUNT语句

    2019-11-05 09:54:56
    关于数据库中行数统计,无论是MySQL还是Oracle,都有一个函数可以使用,那就是COUNT 尝尝问道以下问题 1、COUNT有几种用法? 2、COUNT(字段名)和COUNT(*)查询结果有什么不同? 3、COUNT(1)和COUNT(*)之间有...
  • 数据库的count()函数

    2019-11-29 16:14:53
    使用mysql进行验证 数据 SELECT COUNT(*) FROM test1; SELECT COUNT(1) FROM test1; #统计了包含空(null)行 ...count(expr)中的expr除了是case when 语句,其余都要加上 or null,才能统计出正确值,即便是...
  • AS 关键字是用来更改列别名 COUNT() 返回查询行数 SELECT COUNT(*) FROM ...HAVING 只用在有group by 语句 HAVING作用就是在 group by 之后添加条件,因为where 在group by 之前就完成了,不可以在group
  • 查询下列数据,number_id重复次数超过2number_id:sql:查询结果:
  • 关于数据库中行数统计,无论是MySQL还是Oracle,都有一个函数可以使用,那就是COUNTCOUNT MySQL官网给出解释是: 1、COUNT(expr) ,返回SELECT语句检索行中expr值不为NULL数量。结果是一个BIGINT值。 ...
  • 通过having代替where来使用count(1),sum()等函数。譬如如下数据id value1 21 32 33 53 6 可以写个语句统计value分组 select id,sum(value) from table group by id having sum(value)>=5 在这里,可以...
  • 数据库使用中经常使用count关键字,在不考虑Null情况下 count(*),count(1),count(主键),count(rowid)区别如下: count(1)和count(主键)效果类型, 这两个只扫描主键Index就可以得到数据。 count(ROWID)这也...
  • 今天查询下数据库中一个表具体记录数,使用 select count(1) from [tablename],执行起来速度非常慢,所以想看看是否有更好办法,发现,在tabs表已经存在了该表记录数据了,直接运行如下sql就可以了   ...
  • 逐个表统计数据行数,使用Select count语句统计,比较蛮烦,而且慢,可以使用如下语句直接用户下所有表数据行数。 select TABLE_NAME, T.num_rows, T.last_analyzed from tabs T 但是,从tabs表获取数据...
  • 今天在做分页时候一直被无名错误所干扰(也不算错误吧,就是没有达到自己理想结果),想通过hibernate从数据库中找出满足条件记录数,于是使用了以下语句: Query query=this.getSession()....
  • COUNT 返回集合元素个数 DELETE 删除集合所有元素 DELETE() 删除元素下标为x元素,如果x为null,则集合保持不变 对VARRAY非法 DELETE(,) 删除元素下标从X到Y元素,如果X>Y集合保持不变 对VARRAY
  • 首先报该错误原因是因为所操作插入删除数据库命令内容与数据库中所设置字段不符, 比如向数据库中插入3个数据但是实际数据库中却有4个字段,少字段就会产生上述错误。
  • $count = mysql_num_rows($res); if($count == 0) { $file_path = '../images/'; $src=$file_path.$itemlc; @unlink($src); echo $itemlc; echo " <b>deleted</b> <br> "; } } </code>...
  • 1、Oracle数据库内调用单个shell变量 lv_table=T1 sqlplus / as sysdba <<EOF #<<EOF必须紧跟在上述命令后以一个空格分开 select count(*) from $lv_table; EOF [oracle@lissen db_sh]$ ./exec_...
  • 使用Hibernate如何获得数据库中的数据总量最近在学习JAVA过程中使用到了Hibernate,发现它是一个很好东东,使用它可以很easy数据库进行访问和操作。今天在使用Hibernate时候需要对获取一张数据库...
  • 数据库表NumTable中的num列中的数据先按减号前半部分排序,再按减号后面部分排序(instr获取某个字符串下标,substring截取字符串,cast ... as 类型将字符串转化为指定类型内容)3.sum 、avg、max、min、count函数...
  • 数据库中的分组

    千次阅读 2016-03-03 21:02:21
    数据库分组作用分组是数据库中数据统计一个重要功能,所谓分组就是将数据库查询得到结果以某些字段作为分割条件将查询结果分成多组,然后我们就可以对每一组数据应用各种统计函数比如max,count等等。...
  • mysql数据库 count() 函数和 sum() 函数用法和区别

    万次阅读 多人点赞 2018-08-06 11:51:55
    1、mysql 数据库中 count() 函数是统计查询结果中行数,例如我们有下表 user_auth : 使用 count() 函数来查询结果个数,使用如下查询: mysql &gt; select count(*) from user_auth ;     注意...
  • sqlite3_aggregate_count sqlite3_bind_blob sqlite3_bind_double sqlite3_bind_int sqlite3_bind_int64 sqlite3_bind_null sqlite3_bind_parameter_count sqlite3_bind_parameter_index sqlite3_bind_parameter_...
  • 一直有很大的疑问,有的人说count(*)更快,也有的人说count(列名)更快,那到底是谁更快,我将会在本文详细介绍一下到底是count(1),count(*)和count(列明)的区别,和更适合的使用场景。  往常在工作有人会说...
  • Oracle数据库各类控制语句的使用是本文我们主要要介绍的内容,包括一些逻辑控制语句、Case when的使用、While的使用以及For的使用等等,接下来我们就开始一一介绍这部分内容,希望能够对您有所帮助。 Oracle 逻辑...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,062
精华内容 824
关键字:

数据库中count的使用