count(*)/count(1)/count(主键)统计效率对比

本文通过实验对比COUNT(1), COUNT(*)与COUNT(主键)及COUNT(非主键)在MySQL 5.7 InnoDB引擎下的性能差异,揭示了COUNT函数的实际执行效率,并解析不同场景下COUNT函数的行为特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在实际业务开发中,我们常常需要count数据表的记录条数。关于使用mysql的count统计函数,大多开发者都不会有疑问,但是就使用细节上,大家的观点可能就不一致了。一派认为count(1)比count(*)要快,说count(*)要全表扫描而count(1)则不用。另一派反之。针对count(主键)和count(1)和count(*),大家几乎一致认为count(主键)效率较慢。那么实际情况是这样么?

本次就来做个总结。

测试

针对mysql5.7 innodb引擎,主键为id的表,
我们explain count(1)和count(*)以及count(id)和count(name)

explain select SQL_NO_CACHE count(1) from province
explain select SQL_NO_CACHE count(*) from province
explain select SQL_NO_CACHE count(id) from province
explain select SQL_NO_CACHE count(name) from province

然后发现前三者的执行计划一摸一样
1.png
而count(name)显然效率较低
2.png

所以我们确定count(*)和count(1)以及count(主键)的效率是一致的!
mysql底层对count()有优化,会选择最有效率的方式去执行count操作,两者没有性能差异,效率都比较高。

总结

一方面

count(主键列),count(),count(1)效率差不多!
count(非主键列)的效率往往低于count(
),count(1),count(主键列)!

另一方面

count(1),count(*)会统计表中的所有的记录数,包含字段为null 的记录;
count(列名) 会统计该字段在表中出现的次数,不统计字段为null 的记录。

请关注我的订阅号

订阅号.png

<think>好的,我需要帮助用户正确创建包含Customer、Orders和Lineitem表的SQL结构,并实现Proc_CalTotalPrice存储过程来计算totalprice字段。首先,我需要回顾用户之前的问题和我的回答,以及用户提供的引用内容。 用户之前创建了一个存储过程Proc_CalTotalPrice,用于更新Orders表中的totalprice字段,计算方式是来自Lineitem表的extendedprice乘以(1-discount)(1+tax)的总和。现在用户提到需要创建这三个表的结构,并确保存储过程的正确性。 首先,根据引用[1]中的存储过程示例,用户之前可能尝试过类似的代码,但可能存在语法问题。比如原来的存储过程使用了“AS BEGIN”在MySQL中可能不适用,因为MySQL使用BEGIN...END包裹过程体,而不需要AS。此外,用户之前的示例中可能没有正确设置分隔符,导致创建存储过程时出错。 接下来,用户需要创建Customer、Orders和Lineitem表。根据常见的数据库设计模式,这三个表可能的关系是:Customer有客户信息,Orders是订单主表,Lineitem是订单明细。因此,Orders表应包含orderkey作为主键,以及customerkey作为外键关联Customer表。Lineitem表应包含orderkey作为外键关联Orders,同时有extendedprice、discount、tax等字段用于计算总价。 在创建表结构时,需要注意字段的数据类型和约束。例如,decimal类型适合存储金额,确保精度。外键约束需要正确引用主表的对应字段,并考虑ON DELETE和ON UPDATE的行为。 然后,存储过程的实现需要正确计算totalprice。根据引用[1]中的示例,存储过程应使用UPDATE语句,将Orders的totalprice设置为Lineitem中对应订单的sum(extendedprice*(1-discount)*(1+tax))。需要注意的是,在MySQL中,创建存储过程前可能需要更改分隔符,以避免分号被误认为语句结束。 此外,用户可能需要考虑事务处理和错误处理,如引用[2]中提到的分区字段和性能优化,以及引用[3]中的分布式事务处理。不过,当前需求主要是语法和逻辑正确性,因此事务处理可能不是首要问题,但可以建议添加以提高健壮性。 最后,用户可能需要验证存储过程的执行,确保totalprice正确更新,并检查是否存在性能问题,如引用[2]提到的分区裁剪和字段函数使用的影响。例如,确保WHERE条件中的字段类型匹配,避免使用函数导致索引失效。 总结步骤: 1. 创建Customer、Orders、Lineitem表,正确设置主键和外键。 2. 定义存储过程Proc_CalTotalPrice,使用正确的语法计算totalprice。 3. 处理可能的分隔符问题(MySQL需要DELIMITER命令)。 4. 验证存储过程的执行和结果。 5. 考虑添加事务和错误处理以提高可靠性。 需要确保所有SQL语句的语法正确,特别是MySQL中存储过程的创建方式,与外键约束的正确性。同时,示例中的存储过程可能需要调整,比如在MySQL中使用正确的变量和循环结构(如果适用)。</think>根据您的需求,以下是创建完整表结构和存储过程的规范实现,结合了SQL标准与MySQL特性: ### 一、表结构创建(MySQL语法) ```sql -- 客户表 CREATE TABLE Customer ( customerkey INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, address VARCHAR(100), phone CHAR(11) ) ENGINE=InnoDB; -- 订单表 CREATE TABLE Orders ( orderkey INT PRIMARY KEY AUTO_INCREMENT, orderdate DATE NOT NULL, customerkey INT NOT NULL, totalprice DECIMAL(10,2) DEFAULT 0.00, INDEX idx_customer (customerkey), CONSTRAINT fk_customer FOREIGN KEY (customerkey) REFERENCES Customer(customerkey) ON DELETE CASCADE ) ENGINE=InnoDB; -- 订单明细表 CREATE TABLE Lineitem ( linenumber INT AUTO_INCREMENT, orderkey INT NOT NULL, extendedprice DECIMAL(10,2) NOT NULL, discount DECIMAL(3,2) DEFAULT 0.00, tax DECIMAL(3,2) DEFAULT 0.00, PRIMARY KEY (linenumber, orderkey), CONSTRAINT fk_order FOREIGN KEY (orderkey) REFERENCES Orders(orderkey) ON DELETE CASCADE ) ENGINE=InnoDB; ``` 关键设计要点: 1. 使用`DECIMAL`类型确保金额计算精度 2. 外键约束维护数据完整性[^3] 3. 组合主键`(linenumber, orderkey)`符合订单明细业务特性 4. `ON DELETE CASCADE`实现级联删除[^4] ### 二、存储过程实现 ```sql DELIMITER $$ CREATE PROCEDURE Proc_CalTotalPrice() BEGIN -- 开启事务保证原子性 START TRANSACTION; UPDATE Orders o SET totalprice = ( SELECT SUM( extendedprice * (1 - COALESCE(discount,0)) * (1 + COALESCE(tax,0)) ) FROM Lineitem li WHERE li.orderkey = o.orderkey ); -- 异常处理 IF ROW_COUNT() = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'No records updated'; END IF; COMMIT; END$$ DELIMITER ; ``` 核心特性: 1. `COALESCE`处理空值避免计算错误[^2] 2. `ROW_COUNT()`校验更新结果 3. 自定义错误代码`45000`用于异常反馈 4. 事务控制保障数据一致性[^3] ### 三、验证执行 ```sql -- 调用存储过程 CALL Proc_CalTotalPrice(); -- 验证计算结果 SELECT o.orderkey, o.totalprice, SUM(li.extendedprice*(1-li.discount)*(1+li.tax)) AS calc_total FROM Orders o JOIN Lineitem li ON o.orderkey = li.orderkey GROUP BY o.orderkey; ``` ### 四、优化建议 1. 添加索引加速查询: ```sql ALTER TABLE Lineitem ADD INDEX idx_orderkey (orderkey); ``` 2. 参数化存储过程(示例): ```sql CREATE PROCEDURE Proc_CalTotalPriceByOrder(IN order_id INT) BEGIN UPDATE Orders SET totalprice = (...) WHERE orderkey = order_id; END ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码哥说

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

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

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

打赏作者

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

抵扣说明:

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

余额充值