Day84-count(1)和count(*)哪个效率高?

本文比较了count(1)、count(*)和count(列名)在大数据量、执行效率及对NULL值处理上的差异,指出count(1)在特定情况下可能更快,但count(*)通常由SQL自动优化,实际应用中基本无太大差别。

count(1)和count(*)对比

当表的数据量大些时,对表作分析之后,使用 count(1)还要比使用 count(*)用时多了!

从执行计划来看, count(1) 和 count()的效果是一样的。但是在表做过分析之后, count(1) 会比 count()的用时少些(1w以内数据量),不过差不了多少。

如果 count(1)是聚索引,那肯定是 count(1)快,但是差的很小。因为 count()自动会优化指定到那一个字段,所以没必要去 count(1),用 count() sql会帮你完成优化的,因此:count(1) 和 count(*)基本没有差别!

count(1)和count(列名)对比

两者的主要区别是:

count(1) 会统计表中的所有的记录数,包含字段为 null 的记录。
count(字段) 会统计该字段在表中出现的次数,忽略字段为 null 的情况。即不统计字段为 null 的记录。

count(*)、count(1)和count(列名)区别

执行效果上:

  • count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
  • count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
  • count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计。

执行效率上:

  • 列名为主键, count(列名) 会比 count(1)快
  • 列名不为主键, count(1) 会比 count(列名)快
  • 如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*)
  • 如果有主键,则 selectcount(主键) 的执行效率是最优的
  • 如果表只有一个字段,则 selectcount(*)最优。
/****************************************************************************** * Copyright (c) 2018-2020 TP-Link Systems Inc. * * 文件名称: record_plan.c * 版 本: 1.0 * 摘 要: record_plan源文件 * 作 者: Deng Peng<dengpeng@tp-link.com.cn> * 创建时间: 2019-2-22 ******************************************************************************/ #include <nvmp_utils.h> #include <error.h> #include <unistd.h> #include "slp_model.h" #include "libds.h" #include "record_plan.h" #define DAY_LAST_MINUTES (24 * 60) LOCAL S32 s_timer_id = -1; /* 定时器id */ /* 当前录像计划类型 */ static REC_TYPE_E rec_plan_type = REC_TYPE_MAX; void rec_plan_timer_fun(S32 param); /* 定时器到期调用函数 */ /* 向录像模块发送录像动作 */ /* 注意这里type的枚举值是REC_TYPE_E,不是REC_PLAN_TYPE_E */ S32 notify_outer_module(REC_TYPE_E type) { REC_ACTION rec_action; S32 ret = ERROR; if (type < REC_TYPE_NULL || type >= REC_TYPE_MAX) { RECORD_ERROR("invalid rec_type"); return ERROR; } rec_action.rec_type = type; ret = msg_send(REC_PLAN_ACTION_CHANGED,(U8 *) &rec_action, sizeof(REC_ACTION)); RECORD_DEBUG("REC_TYPE_E type[%d], return %d", type, ret); return ret; } /****************************************************************************** * 函数名称: do_rec_plan() * 函数描述: 执行录像计划, 若当前时间在录像时间段内,则向录像模块发送dms消息(告知:录像类型,录像/停止录像) 并设置定时器到下次启动时间再次调用本函数 * 输 出: N/A * 返 回 值: ERROR/OK * 备 注: 目前只处理当天内的录像计划,若当天没有计划,则定时到当天的最后一秒再次调用本函数 ******************************************************************************/ static S32 do_rec_plan() { int i; S32 ret = OK; PTR_REC_PLAN ptr_rec_plan = NULL; PTR_REC_PLAN_SECTION p_rec_plan_section = NULL; time_t now; struct tm *tm_now; int now_minute; WEEK_DAY wday = 0; S32 next_start_seconds; S32 next_start_minute; ptr_rec_plan = get_rec_plan_cfg(); if (ptr_rec_plan == NULL) { RECORD_ERROR("get_rec_plan_cfg failed"); ret = ERROR; goto end; } /* 如果“SD卡录像”选项关闭,则发送一个停止录像消息,然后返回 */ if (FALSE == ptr_rec_plan->b_enable) { rec_plan_type = REC_TYPE_NULL; notify_outer_module(REC_TYPE_NULL); return OK; } now = time(NULL); tm_now = localtime(&now); now_minute = tm_now->tm_hour * 60 + tm_now->tm_min; /* 查找当前时间所在的录像计划时间段 */ wday = (tm_now->tm_wday + 6) % 7; /* tm_wday: 0-sunday, 1-monday,而录像计划数组的顺序为0-MONDAY,1-Tuesday,...*/ p_rec_plan_section = (PTR_REC_PLAN_SECTION) &(ptr_rec_plan->week_rec_plan->plan_section[wday * MAX_SECTION_PER_DAY]); for (i = 0; i < MAX_SECTION_PER_DAY; i++) { RECORD_DEBUG("section[%d] type[%u] sm[%u] em[%u]", i, p_rec_plan_section[i].type, p_rec_plan_section[i].start_minute, p_rec_plan_section[i].end_minute); if (p_rec_plan_section[i].type == REC_PLAN_TYPE_NULL) { continue; } /* 找到了当前时间所在的录像计划的时间段,依次做3件事: * 1、计算本次录像时段的剩余时间-next_start_seconds * 2、根据录像类型向录像模块发送消息 * 3、设置定时器,next_start_seconds后再次调用本函数*/ if ((p_rec_plan_section[i].start_minute <= now_minute) && (p_rec_plan_section[i].end_minute > now_minute)) { RECORD_DEBUG("section:%d start_minute:%d end_minute:%d now:%d", i, p_rec_plan_section[i].start_minute, p_rec_plan_section[i].end_minute, now_minute); /* 计算距离本时间段结束的时间,单位() */ next_start_seconds = (p_rec_plan_section[i].end_minute - now_minute - 1) * 60 + (60 - tm_now->tm_sec); switch (p_rec_plan_section[i].type) { case REC_PLAN_TYPE_EVENT: rec_plan_type = REC_TYPE_MOTION; /* 通知storage模块当前处于移动侦测录像计划;是否有移动侦测事件发生由storage自行判断 */ notify_outer_module(REC_TYPE_MOTION); break; case REC_PLAN_TYPE_TIME: rec_plan_type = REC_TYPE_TIME; /* 向录像模块发送 定时录像指令 */ notify_outer_module(REC_TYPE_TIME); break; default: rec_plan_type = REC_TYPE_NULL; /* 既不是移动侦测录像,也不是定时录像,则表明发生了错误 */ RECORD_ERROR("do_rec_plan: [%d-%d] invalid record type [%u]", p_rec_plan_section[i].start_minute, p_rec_plan_section[i].end_minute, p_rec_plan_section[i].type); return ERROR; } goto start_timer; } } /* 当前时间不在录像时间段内,发送停止录像的消息 */ rec_plan_type = REC_TYPE_NULL; notify_outer_module(REC_TYPE_NULL); /* 查找最近的录像计划时间段的开始时间 */ next_start_minute = DAY_LAST_MINUTES; for (i = 0; i < MAX_SECTION_PER_DAY; i++) { if (p_rec_plan_section[i].type != REC_PLAN_TYPE_NULL) { if ((p_rec_plan_section[i].start_minute > now_minute) && (p_rec_plan_section[i].start_minute < next_start_minute)) { next_start_minute = p_rec_plan_section[i].start_minute; } } } /* 计算距离下一次录像时段开始时间的秒数 */ next_start_seconds = (next_start_minute - now_minute - 1) * 60 + 60 - tm_now->tm_sec; start_timer: s_timer_id = inet_add_timer(rec_plan_timer_fun, 0, next_start_seconds, EXECUTE_SINGLE); if (ERROR == s_timer_id) { RECORD_ERROR("inet_add_timer return ERROR"); } end: return ret; } void rec_plan_timer_fun(S32 param) { do_rec_plan(); } /* 系统时间更新消息的回调函数 */ S32 ntp_time_reload_cb(void *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { TIME_CALIBRATION *time_cali = NULL; if (mbuf == NULL || mlen != sizeof(TIME_CALIBRATION)) { return ERROR; } time_cali = (TIME_CALIBRATION *)mbuf; /* 校时失败什么都不做 */ if (time_cali->status != TIME_CALIBRATION_SUCC) { return OK; } /* 删除系统时间更新前设置的定时器 */ if (ERROR != s_timer_id) { inet_del_timer(s_timer_id); s_timer_id = ERROR; } /* 系统时间更新后,立即执行一次录像计划 */ return do_rec_plan(); } /***************************************************** * 下面是本模块作为cap子模块的配套函数 *****************************************************/ LOCAL S32 record_plan_init() { S32 ret = OK; /* 初始化录像计划结构体 */ ret = rec_plan_init(); if (ERROR == ret) { RECORD_INFO("rec_plan_init fail"); return ret; } /* 关注系统时间更新消息 */ ret = msg_attach_handler(TIME_CALIBRATION_MSG_ID, ntp_time_reload_cb); if (ERROR == ret) { RECORD_INFO("msg_attach_handler fail"); return ret; } RECORD_INFO("init over, ret[%d]", ret); return ret; } LOCAL S32 record_plan_start() { S32 ret = ERROR; /* 读取本机上的录像计划配置表 */ ret = load_record_plan_cfg(); if (ERROR == ret) { RECORD_ERROR("load_record_plan_cfg error."); return SLP_EGENERIC; } /* 如果尚未开启定时器,那么立即执行一次录像计划 */ if (ERROR == s_timer_id) { ret = do_rec_plan(); if (ERROR == ret) { RECORD_ERROR("load_record_plan_cfg error."); return SLP_EGENERIC; } } RECORD_INFO("start over, ret[%d]", ret); return ret; } S32 record_plan_reload() { S32 ret = OK; /* 读取新的录像计划配置表 */ ret = load_record_plan_cfg(); if (ERROR == ret) { RECORD_ERROR("load_record_plan_cfg error."); return SLP_EGENERIC; } /* 更新录像计划配置表后,删除先前的定时器,然后执行一次录像计划 */ if (ERROR != s_timer_id) { inet_del_timer(s_timer_id); s_timer_id = ERROR; } ret = do_rec_plan(); if (ERROR == ret) { RECORD_ERROR("load_record_plan_cfg error."); return SLP_EGENERIC; } RECORD_INFO("reload over, ret[%d]", ret); return SLP_ENONE; } LOCAL S32 record_plan_stop() { msg_detach_handler(TIME_CALIBRATION_MSG_ID, ntp_time_reload_cb); if (ERROR != s_timer_id) { inet_del_timer(s_timer_id); s_timer_id = ERROR; } RECORD_INFO("record plan stop over."); return SLP_ENONE; } #define WEEK_PATH_SUFFIX_SIZE 5 /* listConfig路径后缀最大长度为4,加上\0占5字节 例如:_168 */ LOCAL S32 record_plan_check(BIN_AREA *bin_area) { REC_PLAN_SECTION plan_section; char record_path_str[sizeof(REC_PLAN_WEEK_PATH) + WEEK_PATH_SUFFIX_SIZE] = {0}; S32 section_count = 0; for (section_count = 0; section_count < WEEK_PLAN_LIST_SIZE; ++section_count) { memset(&plan_section, 0, sizeof(REC_PLAN_SECTION)); snprintf(record_path_str, sizeof(record_path_str), "%s_%d", REC_PLAN_WEEK_PATH, section_count + 1); if (0 != ds_ext_read(bin_area, record_path_str, (U8 *)&plan_section, sizeof(REC_PLAN_SECTION))) { if (plan_section.start_minute > 1440 || plan_section.end_minute > 1440) { return SLP_EINVARG; } } } return SLP_ENONE; } LOCAL void record_plan_main() { /*************************************************************************************/ /********* Desc of /record_plan/chn1_channel *********************************************/ /*************************************************************************************/ DS_OPT_DESC chn1_channel_options[] = { DS_SWITCH_OPT(REC_PLAN_ENABLE, enabled, OPT_FLAG_NORM), }; DS_SEG_DESC chn1_channel_segments[] = { DS_STRUCT_SEG("chn1_channel", SEG_LIM_RW, SEG_GROUP_ROOT, REC_PLAN_ENABLE, chn1_channel_options), }; DS_SECT_DESC chn1_channel_sections[] = { DS_STRUCT_SECT("chn1_channel", chn1_channel_segments), }; /*************************************************************************************/ /********* Desc of /record_plan/chn1_channel *********************************************/ /*************************************************************************************/ DS_OPT_DESC week_plan_options[] = { DS_U8_OPT(REC_PLAN_SECTION, type, OPT_FLAG_NORM), DS_U16_OPT(REC_PLAN_SECTION, start_minute, OPT_FLAG_NORM), DS_U16_OPT(REC_PLAN_SECTION, end_minute, OPT_FLAG_NORM), }; DS_SEG_DESC week_plan_segments[] = { DS_STRUCT_SEG("week_plan", SEG_LIM_RW, SEG_GROUP_ROOT, REC_PLAN_SECTION, week_plan_options), }; DS_TBL_DESC record_plan_tables[] = { DS_STRUCT_TBL("chn1_channel", TBL_ATTR_CFG, chn1_channel_sections), DSLL_TBL("week_plan", TBL_ATTR_LSTCFG, TABLE_FLAG_PREALLOCATE, WEEK_PLAN_LIST_SIZE, segment, week_plan_segments, NELEMENTS(week_plan_segments)) }; DS_DAT_MON_DESC record_plan_data_monitor[] = { DS_DAT_MON(REC_PLAN_ENABLE_PATH, DATA_ATTRI_CHECK), DS_DAT_MON(REC_PLAN_WEEK_PATH, DATA_ATTRI_CHECK), }; DS_MOD_DESC record_plan_module = DS_STRUCT_MOD("record_plan", record_plan_init, record_plan_check, NULL, record_plan_start, record_plan_stop, record_plan_tables, record_plan_data_monitor); MODULE *module_node = ds_register_module("record_plan", &record_plan_module); CAP_ASSERT(NULL != module_node); } CAP_INIT(record_plan_main); 通俗解说一下这段代码
最新发布
08-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿杰杰杰のblog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值