记录一个sql优化后大大提高查询效率的情形

本文介绍了一种通过优化SQL查询来提高数据库查询效率的方法。通过对原始SQL语句的重构,将原本复杂的函数运算分解为简单的条件判断,实现了从4.5秒到0.05秒的查询性能飞跃。

众所周知,sql写得怎么样,对于查询效率的影响是颇大的。下面看一个比较普通的查询:

假设一张表有event_date和event_time2个字段分别表示日期和时间,现在直接给你一个时间字符串,这个时间字符串是“日期+时间”的组合,现在需要按时间范围过滤出一部分数据。如果你不转弯的话,很有可能你会按照惯性思维使用concat(event_date, event_time)连接函数,如:

SELECT A, MAX(B) AS B,SUBSTR(CONCAT(event_date, event_time),1,12)AS tran_time 
       FROM tablename 
            WHERE SUBSTR(CONCAT(event_date, event_time),1,12) >= :start_time  
            AND SUBSTR(CONCAT(event_date, event_time),1,12) < :end_time  
     AND A = :A  	
        GROUP BY A,tran_time  
        ORDER BY A,tran_time ASC

 start_time和end_time是传递过来的由“日期+时间”组合成的字符串。

这是比较容易想到的传统思维,但这种sql语句的查询效率老低了。差不多查一次需要4.5s+, 因为不仅仅需要用到max函数,还需按SUBSTR(CONCAT(event_date, event_time),1,12) 这个计算出来的字段group by,最主要的是在where语句里,对2个时间的字段需要进行多重函数运算后看看那些记录符合你所规定的时间范围~~  这样,在不知不觉中,造成了全表扫描,效率极低,特别是在表中数据量比较大的时候。

 

我们已经知道,如果一张表是数据量比较大的表,并且一般都用与于查询时,索引的使用会给我们带来极大的性能优化。考虑到使用索引,我们应该尽量避免where语句里的字段不进行函数作用(因为即使你对where下的字段建立了索引,但如果你对他们进行了函数运算,索引是失效的),所以我们考虑把它们尽量独立开来。

基于上述思想,改正如下:

先对A, evnet_date和event_time三个字段建立索引。

SELECT A, MAX(B) AS B,SUBSTR(CONCAT(event_date, event_time),1,12)AS tran_time 
       FROM tablename  
            WHERE event_date >= :start_date AND event_time >= :start_time  
       AND event_date <= :end_date AND event_time < :end_time   
     AND A = :A  	
        GROUP BY A,tran_time  
        ORDER BY A,tran_time ASC

 可以看出我们把event_date和event_time的起止时间都“拆”开来了,所以只需在传过来的起止时间字符串上截取响应的日期和时间字符串给sql语句即可。

测试检查发现,2句sql查询出的结果是一致的,说明他们是等效的。

改正之后,发现效率提升至0.05s左右,性能得到极大提升!!!

 

这句优化后的sql语句是突破了sql语句字段去适应外部传过来的时间字符串,而是从sql优化的角度看,让外部的条件去适应sql语句的查询,这种思想我之前很少有,也算是一种思维的突破了!

### 大型数据库表性能与存储优化方法 #### 1. **优化思路** 针对大型数据库表的性能存储优化,可以从以下几个方面入手:硬件、系统配置、数据库表结构以及 SQL 索引的设计。从优化成本的角度来看,硬件的成本最高,其次是系统配置、数据库表结构 SQL索引[^1]。然而,从优化效果的角度看,则是相反的趋势——SQL 索引优化的效果最佳,其次为数据库表结构调整,再次为系统配置调整,最后才是硬件升级。 --- #### 2. **表分区优化** ##### (1) **分区键选择** 选择合适的分区键对于表分区的效果至关重要。分区键应当是经常被查询过滤的列,这样能够在查询时快速定位到目标分区。此外,还需要考虑数据的均匀分布未来的扩展性。例如,在销售数据表中,可以根据日期、地区或产品类别等字段进行分区[^2]。 ##### (2) **子分区** 如果单一的分区仍然过大,可能会导致查询性能下降。此时可以通过引入子分区来进一步细分数据。子分区可以依据更具体的条件(如地区、销售人员或产品类型)对已有分区进行细化分割,从而更加精准地定位所需数据并提升查询效率[^2]。 ##### (3) **分区策略** 根据数据特性查询需求,可选用不同的分区策略: - 范围分区(RANGE PARTITIONING):适合按时间序列或其他有序属性划分的数据集。 - 列表分区(LIST PARTITIONING):用于基于离散值集合划分的情况。 - 哈希分区(HASH PARTITIONING):适用于需要均匀分布数据的情形。 - 键分区(KEY PARTITIONING):类似于哈希分区,但采用 MySQL 内部算法实现。 - 组合分区(COMPOSITE PARTITIONING):允许嵌套使用两种以上的分区方式,比如先按范围再按哈希[^4]。 ##### (4) **分区维护** 定期执行必要的分区维护操作有助于保持良好的性能表现。这些操作包括但不限于分区合并、拆分、移动及压缩等措施。通过科学规划实施此类活动,不仅可以降低分区数量还能有效改善存储空间利用状况进而增强整体效能水平。 ##### (5) **分区索引** 为了最大化分区带来的好处,应该精心挑选适当的索引方案配合已建立起来的各个独立部分工作流程一起运作良好;特别是当涉及到频繁访问特定区域内的记录时候更是如此因为这将显著加快检索速度同时减少不必要的全盘扫描动作发生几率大大提高了系统的响应速率同时也减轻了服务器负载压力[^2]. --- #### 3. **索引优化** 索引作为加速查询的核心工具之一,在处理海量数据的大表时尤为重要。以下是几个关键点: - 针对那些在 WHERE 条件或者 JOIN 过程中的高频使用的字段创建索引。 - 使用覆盖索引来确保某些简单查询可以直接由索引树完成而不需要回表读取原始行数据。 - 对于复合索引来说要注意顺序安排使得最具有区分度的那个维度放在前面位置以获得更好的筛选能力。 下面是一个简单的例子展示如何构建有效的索引: ```sql CREATE INDEX idx_order_date ON orders(order_date); CREATE INDEX idx_customer_id_order_status ON orders(customer_id, order_status); ``` 这里第一个单独建立了关于订单日期上的普通二级索引方便做时间段统计分析类任务第二则组合成了双栏位形式兼顾到了客户身份识别同时还照顾到了状态分类这两种不同用途下的高效查找需求[^1]。 --- #### 4. **其他建议** 除了以上提到的技术手段外还有几点额外需要注意的地方可以帮助我们更好地管理调优大规模的关系型数据库环境: - 合理分配磁盘 I/O 资源给不同的文件组/表空间,避免热点竞争引发瓶颈现象; - 定期清理不再需要的历史陈旧资料释放宝贵的空间资源; - 如果可能的话尝试垂直切片技术即将一张宽表分解成若干窄表各自承担一部分职责领域以此达到简化复杂度的目的同时也能一定程度缓解单张巨量级表格所带来的管理困难局面[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值