分区表的查询

  前一篇文章提到了在2014下分区表引起的奇葩问题,最近也在苦苦研究问题的原因。这篇文章主要讲述在分区表下,查询是怎么样的一个情况。由于2014的新功能“参数估计”下是如何运转的目前无从得知,所以只能分享下2008下的原理了...

  在 SQL Server 2008 中,已分区表的内部表示形式已发生变化,即已分区表将作为一个多列索引呈现给查询处理器,其中 PartitionID是第一列。PartitionID 是一个隐藏的计算列,用于在内部表示包含特定行的分区的 ID。例如,假设一个定义为 T(a, b, c) 的表 T 在 a列进行了分区,并在 b 列的聚集索引。在 SQL Server 2008 中,此分区表在内部被视为一个具有架构 T(PartitionID, a, b, c) 的未分区表,并具有组合键 (PartitionID, b) 的聚集索引。这样查询优化器便可以基于 PartitionID 对任何已分区表或索引执行查找操作。

  此外,查询优化器的功能也得以扩展,可以针对 PartitionID(作为逻辑首列)以及其他可能的索引键列执行某一条件下的查找或扫描操作,然后,对于符合第一级查找操作的条件的每个不同值,再针对一个或多个其他列执行不同条件下的二级查找。也就是说,这种称为“skip-scan”的操作允许查询优化器基于某一条件来执行查找或扫描操作以确定要访问的分区,然后在该运算符内执行一个二级索引查找操作以返回这些分区中符合另一个不同条件的行。例如,请考虑以下查询。

  SELECT * FROM T WHERE a < 10 and b = 2;

对于本示例,假设定义为 T(a, b, c) 的表 T 对 a 列进行了分区,并具有 b 的聚集索引。表 T 的分区边界由以下分区函数定义:

  CREATE PARTITION FUNCTION myRangePF1 (int) AS RANGE LEFT FOR VALUES (3, 7, 10);

  为求解该查询,查询处理器将执行第一级查找操作以查找包含符合条件 T.a < 10 的行的每个分区。这将标识要访问的分区。然后,在所标识的每个分区内,处理器将针对 b 列的聚集索引执行一个二级查找以查找符合条件 T.b = 2 和 T.a < 10 的行。

下图所示为跳跃扫描操作的逻辑表示形式,其中显示了在 a 列和 b 列中包含数据的表 T。分区编号为 1 到 4,分区边界由垂直虚线表示。对分区执行的第一级查找操作(图中未显示)已确定分区 1、2 和 3 符合查找条件(由为该表定义的分区和 a 列的谓词指示),即T.a < 10。曲线指示了跳跃扫描操作的二级查找部分所遍历的路径。实际上,跳跃扫描操作将在这些分区的每个分区中查找符合条件 b = 2 的行。跳跃扫描操作的总开销等于三个单独索引查找之和。

显示跳过扫描操作。

 

 

-------已分区堆的执行计划------------------------------------------------------

  

  已分区堆被视为分区 ID 的逻辑索引。已分区堆的分区排除在执行计划中表示为一个 Table Scan 运算符,其中对分区 ID 使用了 SEEK 谓词。下面的示例显示了所提供的显示计划信息:

|-- Table Scan (OBJECT: ([db].[dbo].[T]), SEEK: ([PtnId1001]=[Expr1011]) ORDERED FORWARD)

 

 

------归置联接的执行计划--------------------------------------------------------

  使用相同或等效的分区函数对两个表进行分区并且在查询的联接条件中指定了来自联接两侧的分区依据列时就会发生联接归置。查询优化器可以生成一个计划,其中具有相等分区 ID 的每个表的分区将分别联接在一起。归置联接可能比非归置联接的执行速度快,因为前者可以只需较少的内存和处理时间。优化器会基于成本估计来选择非归置计划或归置计划。

在归置计划中,Nested Loops 联接从内侧读取一个或多个联接表或索引分区。Constant Scan 运算符内的数字表示分区号。

为已分区表或索引生成归置联接的并行计划时,在 Constant Scan 和 Nested Loops 联接运算符之间会出现一个 Parallelism 运算符。在此情况下,在联接外侧的多个线程会各自在不同的分区上进行读取和操作。

下图显示了一个归置联接的并行查询计划。

归置联接的执行计划

 

 

------并行查询执行策略--------------------------------------------------------

  查询处理器对从已分区对象选择的查询使用查询执行策略。作为执行策略的一部分,查询处理器会确定查询所需的表分区,以及要分配给每个分区的线程比例。在大多数情况下,查询处理器会为每个分区分配数量相等或几乎相等的线程,然后在这些分区中并行地执行查询。以下几段更详细地介绍了线程分配情况。

如果线程数小于分区数,则查询处理器会将每个线程分配给一个不同的分区,最初会有一个或多个分区没有获得分配的线程。当线程完成在一个分区上的执行时,查询处理器会将它分配给下一个分区,直到每个分区都分配有一个线程。这是查询处理器将线程重新分配给其他分区的唯一情况。

显示在完成后重新分配的线程

如果线程数与分区数相等,则查询处理器会为每个分区分配一个线程。当线程完成时,不会重新分配给另一个分区。

显示给每个分区分配一个线程

如果线程数大于分区数,则查询处理器会为每个分区分配相等数量的线程。如果线程数并非恰好是分区数的倍数,则查询处理器会为某些分区额外分配一个线程,以使用所有可用线程。请注意,如果只有一个分区,则会将所有线程都分配给该分区。在下图中,有四个分区和 14 个线程。每个分区都分配有 3 个线程,两个分区具有一个额外的线程,总共分配了 14 个线程。当线程完成时,不会重新分配给另一个分区。

显示给分区分配多个线程

尽管以上示例指出了一种分配线程的简单方式,但实际策略要复杂一些,并需要考虑在查询执行过程中出现的其他变化因素。例如,如果表已分区,并在 A 列上有一个聚集索引,并且查询有谓词子句 WHERE A IN (13, 17, 25),则查询处理器将为这三个查找值(A=13、A=17 和 A=25))各分配一个或多个线程,而不是为每个表分区分配一个或多个线程。只需在包含这些值的分区中执行查询,并且如果所有这些查找谓词都恰好在同一个表分区中,则所有线程都将分配给同一个表分区。

为了举出另一个示例,假定表在 A 列上有四个分区(边界点为 (10, 20, 30)),在 B 列上有一个索引,并且查询有一个谓词子句WHERE B IN (50, 100, 150)。因为表分区是基于值 A,所以值 B 可以出现在任何表分区中。这样,查询处理器将分别在四个表分区中查找三个 B 值 (50, 100, 150) 中的每一个值。查询处理器将按比例分配线程,以便它可以并行执行 12 个查询扫描中的每一个扫描。

 

基于 A 列的表分区

在每个表分区中查找 B 列

表分区 1:A < 10

B=50, B=100, B=150

表分区 2:A >= 10 AND A < 20

B=50, B=100, B=150

表分区 3:A >= 20 AND A < 30

B=50, B=100, B=150

表分区 4:A >= 30

B=50, B=100, B=150

转载于:https://www.cnblogs.com/double-K/p/5503379.html

<think>好的,我现在需要回答用户关于达梦数据库中带分区表查询的问题。首先,我需要回顾之前对话的内容,确保这次回答的一致性和准确性。用户之前询问过多字段范围分区的支持情况,我解释了达梦不支持多字段范围分区,但提供了替代方案,比如虚拟列和组合分区。现在用户的问题是“带分区表查询”,我需要详细说明在达梦数据库中如何进行分区表查询操作,以及相关的注意事项和优化建议。 首先,我应该明确什么是分区表查询分区表查询指的是对已经分区的表进行数据检索时,如何利用分区特性来提高查询效率。这可能包括查询特定分区的数据、跨分区的查询优化,以及分区剪裁(Partition Pruning)等技术。 接下来,我需要考虑达梦数据库的分区类型。根据之前的回答,达梦支持范围分区、列表分区、哈希分区,以及组合分区。每种分区类型在查询时可能有不同的优化策略。例如,范围分区适合按时间范围查询,列表分区适合按特定值查询,哈希分区则用于均匀分布数据。 然后,我需要说明在达梦中进行分区表查询的基本方法。包括直接查询整个表,或者指定特定分区进行查询。例如,使用SELECT * FROM table PARTITION (partition_name)来查询特定分区的数据。同时,可能需要提到在WHERE子句中使用分区键的条件,以便数据库自动进行分区剪裁,减少扫描的数据量。 此外,还需要讨论分区剪裁的原理和实现。达梦是否自动进行分区剪裁,或者需要用户手动指定。如果自动支持,那么在编查询时,只要条件中包含分区键,优化器会自动排除不需要的分区,提升查询性能。如果用户需要手动指定,可能需要使用特定的语法或提示(Hints)。 接下来,可能需要提到分区表查询的优化策略。例如,如何设计分区键以匹配常见的查询条件,避免全表扫描。同时,索引在分区表中的使用情况,比如本地索引和全局索引的区别,以及它们对查询性能的影响。 另外,组合分区的查询处理也需要解释。例如,如果表是范围-列表组合分区,查询时如何同时利用主分区和子分区的条件进行优化。可能需要举例说明,比如按时间范围主分区和按地区子分区,查询某个时间段内特定地区的数据时,如何有效剪裁分区。 还要注意达梦的Oracle模式下的兼容性。虽然达梦在语法上兼容Oracle的分区查询语句,但实际执行时是否有差异。例如,某些在Oracle中自动优化的查询,在达梦中是否需要调整法才能达到同样的效果。 然后,需要涉及到达梦的文档或官方建议。是否有推荐的最佳实践,比如避免跨分区的大量扫描,或者如何监控分区查询的性能。可能还需要提到一些系统视图或工具,用于分析分区表查询的执行计划,确认是否有效利用了分区剪裁。 此外,用户可能的实际应用场景需要考虑。例如,处理大数据量时,如何通过分区表查询来提升性能,或者在OLAP和OLTP环境中不同的查询策略。可能需要给出示例SQL语句,展示在不同情况下如何编高效的查询。 最后,总结分区表查询的关键点,强调合理设计分区策略和编查询语句的重要性,以及达梦在此方面的支持和限制。同时,可以对比其他数据库(如Oracle)在分区查询方面的异同,帮助用户迁移或适配现有应用。 在整理这些思路时,需要确保语言简洁明了,结构清晰,分点说明。同时,保持与之前回答一致的格式,使用加粗、代码块、列表等元素,提高可读性。避免使用过多技术术语,必要时进行解释,确保用户能够理解。</think>--- ### **达梦数据库分区表查询指南** 在达梦数据库中,**分区表查询** 通过合理利用分区特性可显著提升性能。以下是关键操作方法和优化策略: --- ### **1. 基础查询方式** #### **(1) 全表查询** 直接查询所有分区的数据: ```sql SELECT * FROM sales_data; -- 扫描全部分区 ``` #### **(2) 指定分区查询** 通过 `PARTITION` 子句精准定位分区: ```sql -- 查询特定分区(如按年份划分的 p_2023 分区) SELECT * FROM sales_data PARTITION (p_2023); ``` #### **(3) 自动分区剪裁(Partition Pruning)** 在 `WHERE` 条件中指定 **分区键**,达梦自动过滤无关分区: ```sql -- 假设表按 sale_date 范围分区 SELECT * FROM sales_data WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31'; -- 仅扫描关联分区 ``` --- ### **2. 分区剪裁的触发条件** 达梦优化器自动触发剪裁需满足以下条件: - **条件精准匹配分区键**:如分区键为 `sale_date`,查询条件需直接包含该字段。 - **避免函数或复杂表达式**:条件中若对分区键使用函数(如 `YEAR(sale_date)=2023`),可能无法触发剪裁。 - **组合分区的层级优化**:对 `RANGE-LIST` 等组合分区,需同时指定主分区和子分区键条件。 --- ### **3. 组合分区查询示例** 假设表按 **年份(RANGE)** 和 **地区(LIST)** 组合分区: ```sql -- 创建组合分区表 CREATE TABLE sales_data ( order_id INT, sale_date DATE, region VARCHAR(20) ) PARTITION BY RANGE(sale_date) SUBPARTITION BY LIST(region) ( PARTITION p_2022 VALUES LESS THAN ('2023-01-01') ( SUBPARTITION p_east VALUES ('east'), SUBPARTITION p_west VALUES ('west') ), PARTITION p_2023 VALUES LESS THAN ('2024-01-01') ( SUBPARTITION p_east VALUES ('east'), SUBPARTITION p_west VALUES ('west') ) ); ``` **高效查询法**: ```sql -- 查询 2023 年东部地区数据(仅扫描 p_2023 主分区下的 p_east 子分区) SELECT * FROM sales_data WHERE sale_date >= '2023-01-01' AND region = 'east'; ``` --- ### **4. 执行计划验证** 通过 `EXPLAIN` 分析是否触发分区剪裁: ```sql EXPLAIN SELECT * FROM sales_data WHERE sale_date = '2023-05-01'; ``` **关键输出**: - 若显示 **`PARTITION RANGE SINGLE`** 或 **`PARTITION LIST SINGLE`**,表示成功剪裁。 - 若显示 **`PARTITION RANGE ALL`**,表示未触发剪裁(需优化查询条件)。 --- ### **5. 性能优化建议** | 场景 | 优化策略 | |---------------------|--------------------------------------------------------------------------| | 高频按分区键查询 | 确保查询条件直接使用分区键,避免隐式转换 | | 跨分区查询 | 减少 `BETWEEN` 或 `IN` 的跨度,优先使用等值条件 | | 组合分区查询 | 同时指定主分区和子分区条件,充分利用层级过滤 | | 索引设计 | 对分区键建立本地索引(Local Index),避免全局索引的维护成本 | --- ### **6. 限制与注意事项** - **函数索引不支持分区剪裁**:如分区键为 `MONTH(sale_date)`,需在应用层处理条件。 - **DML 操作锁定范围**:`UPDATE`/`DELETE` 可能锁定整个分区,影响并发性能。 - **统计信息更新**:定期执行 `DBMS_STATS.GATHER_TABLE_STATS` 确保优化器选择正确分区。 --- ### **总结** | 操作 | 达梦支持情况 | 建议 | |---------------------|-------------------|----------------------------------------------------------------------| | 单分区查询 | ✅ 支持 | 使用 `PARTITION` 子句显式指定分区 | | 自动分区剪裁 | ✅ 支持 | 确保查询条件精准匹配分区键数据类型 | | 组合分区查询优化 | ✅ 支持 | 同时指定主分区和子分区条件 | | 分区键使用函数 | ❌ 不支持剪裁 | 改用虚拟列或应用层预处理 | 合理设计分区策略(如按时间、地域划分),配合精准查询条件,可充分发挥达梦分区表的性能优势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值