我有一个大表(几亿行),我想对其进行有效分区。我的问题是分区大小和分区数之间是否存在权衡。据我所知,分区中使用的列上的大多数查询会更快,因为查询(对于大多数查询)只需要在适用于查询的分区内进行搜索。因此,为了最大限度地提高效率,您应该将大表划分为最大数量的分区,从而使每个分区尽可能小是有道理的。对于 MySQL,这意味着 1024 个分区。但是,拥有大量分区是否有任何性能缺陷?是这样,如何找到最佳分区数?
注意:在 stackoverflow 上已经有一个有点类似的问题,但只有一个答案,(从我的角度来看)没有达到目标。所以我会用我自己的方式陈述这个问题......希望它更清楚
我的数据库中有一些非常大的表,但是这些数据中有很大一部分是“旧的”。
由于我无法控制的情况,我不允许删除这些“旧”数据。另一个限制是我无法修改数据库,这意味着向其中添加文件组。现在的情况是,一切都驻留在PRIMARY文件组中。
我想将这些表分成几个分区,例如“新”、“旧”、“存档”等。我确实有一个“状态”列,我想用于此目的。
鉴于所描述的场景和限制,我想知道分区在这里是否有意义。换句话说,如果我的表以这种方式分区,但所有分区都位于同一个文件组中,SQL Server 是否足够聪明,可以在底层文件中找到我的“新”数据所在的特殊区域,而不触及具有“旧”数据的区域?
换句话说,假设我 80% 的数据是“旧的”。SQL Server 是否有一种机制可以避免访问 100% 的底层文件,而只访问 20% 包含“新”数据的内容(当然,假设我WHERE在查询子句中指定了我的分区列)。
我想要回答这个问题,需要了解分区是如何在内部实现的。我很感激任何指点。
我有一个table1在db1和table2在db2上的SQL Server 2008 R2。
如果我做一个选择查询加入两个表,得到结果真的很慢。
一个简单的查询,如
SELECT *
FROM db1.dbo.table1 t1
LEFT JOIN db2.dbo.table2 t2 ON t1.k1 = t2.k2
Run Code Online (Sandbox Code Playgroud)
有时真的很慢。
我不确定这是否对 SQL Server 很常见,并且“必须像规则一样”“不连接来自不同数据库的两个表”。
在那种情况下......我补充说这个问题,我有一个存储在一个字段上的数据库二进制数据,我喜欢与主数据库分开而不增加主表的大小......最好为此对数据库进行分区?
我用两个简单的表进行了测试,但加入这两个表仍然很慢。
在此先感谢您的帮助。
..几年后更新... 24-09-18
确保您加入的字段具有相同的类型、大小和排序规则。
示例:某些属性是 varchar(255) 和另一个 varchar(20) ......这可能是一个问题,因为引擎必须将一种类型转换为另一种类型(发生隐式转换),而有时它运行得更快......如果重新索引或数据库发生一些变化,你可以看到在某个时刻查询开始花费更多的时间来完成......
如果您无法更改字段类型以匹配其中一个 db/tables,请尝试执行显式转换以查看是否可以提高查询速度。用
cast(fieldname as type(size)) = fieldName2)
什么时候不想对数据库进行分区?(思维MySQL 分区)
就我而言
即使是最后一点,查找也不是并行运行的,所以在所有情况下,这是一个胜利吗?分区有什么缺点?为什么不是每个人都默认使用的东西,至少当您查看一百万条以上的记录时?
更新 - 我选择了 zgguy 的答案,但请注意,我在自己的研究结果中添加了自己的答案,包括指向对我非常有用的类似问题的非常好的答案的链接。
我在 SQL Server 2016 中有三个聚集列存储索引 (CCI) 表。所有这些 CCI 都在相同的分区方案中,基于租户 ID。最近,不一致的是,我在从连接到这些表的简单选择语句上遇到了死锁。死锁的示例查询:
SELECT TOP 33 r.tenantid
FROM Table_r r
INNER JOIN Table_cm cm ON r.MyKey=cm.MyKey
INNER JOIN Table_pe pe ON r.MyKey=pe.MyKey
WHERE r.TenantId = 69
AND pe.TenantId = 69
AND cm.TenantId = 69
Run Code Online (Sandbox Code Playgroud)
错误信息:
事务(进程 ID 56)在与另一个进程的通用可等待对象资源上发生死锁,并已被选为死锁受害者。重新运行事务。
线索:
sql-server deadlock partitioning columnstore sql-server-2016
我最近继承了一个使用日期分区的项目,其中每日计划任务实现了过去 30 天和未来 60 天的滑动窗口方案。
实际上,插入的数据SYSUTCDATETIME()用于分区列,因此未来的 60 个分区始终为空。
这是一个需要解决的问题还是我应该让睡狗撒谎?
背景:我们的数据库中有两个相当大的表,一个包含 8000 万条记录,另一个包含 1.6 亿条记录。我们看到了性能问题,并正在考虑对这两个表使用表分区。
我的问题是:是否有很多记录表明我们应该分区或不分区以保持良好的性能?我知道没有“一刀切”的答案,但可能有一个一般性建议,例如“传递了 X 百万条记录,您应该对表进行分区”。有很多关于如何分区的指导,但没有关于“何时”的指导。
如果我使用ntext、text或image数据类型对表进行分区并使用 重建单个分区上的索引online = off,这会锁定整个表还是仅锁定有问题的分区?
我有一个由四个聚集列存储索引表 (CCI) 和九个行存储表组成的数据仓库。这些表仅用于分析,并且每 15 分钟从临时表中插入 CCI 数据。我希望通过添加分区和排序来优化查询性能。
该数据的所有查询都基于一个包含大约 350 个不同值的整数字段。最左边的 CCI 有 100M 条记录和 125 列。有三个子 CCI 具有相同的整数字段。CCI 2 有 1500 万条记录和 150 列,CCI 3 和 4 都有大约 3000 万条记录和 25 列。
在这 350 个不同的整数中,最左边表中的记录数分布如下:
此外,还有其他九个行存储表也连接到 CCI。它们具有涓流插入,是 CCI 的子项,它们都包含相同的整数字段。这些行存储具有相似或更小的记录量,每个 < 10 列,两个包含 LOBS,两个经常进行大规模更新(这些更新也基于 ID 字段)。
我应该做多少个分区?
我还应该对行存储表进行分区吗?
是否有我忽略的重要考虑因素?
关于我之前提到的“排序”的注意事项:
最左边的 CCI 中的日期字段通常是这些查询中的次要谓词,因此我正在考虑每四个星期左右按日期重新排序 CCI 作为维护。我将通过删除 CCI、在日期上添加聚集行存储索引、删除该索引,然后使用 MAXDOP=1 重新添加 CCI 来实现这种排序。我也在考虑通过其父级的连接键对子 CCI 进行排序。
PARTITION我目前正在探索, 对于我的特定用例的使用。
\n我使用 InnoDB,每个表一个文件。玛丽亚数据库 10.8。
我正在阅读 Rick 的PARTITION Maintenance in MySQL网页。
\n我想强调这一点:
\n\n\n\n
WHERE X = 1234-- 这使得“分区修剪”仅在该一个分区中查找。但这并不比INDEX(x)在非分区表上好。无论如何,您可能都需要该索引;在第一次“修剪”到所需的分区后,您仍然需要索引。没有更快。
\n一个常见的谬误:“分区将使我的查询运行得更快”。不会的。思考“点查询”需要什么。没有分区,但有适当的索引,有一个 BTree(索引)可以向下钻取以找到所需的行。对于 10 亿行,这可能是 5 层深。通过分区,首先选择并“打开”分区,然后向下钻取较小的 BTree(例如 4 层)。嗯,较浅 BTree 的节省被必须打开分区所消耗。同样,如果您查看需要访问的磁盘块,以及其中哪些块可能会被缓存,您会得出结论:可能有大约相同数量的磁盘命中。由于磁盘命中是查询中的主要成本,因此分区不会获得任何性能(至少对于这种典型情况)。二维情况(如下)给出了该讨论的主要矛盾。
我完全明白这意味着什么,但我有一个问题:
\n在 MySQL/MariaDB 中,索引的性能会随着索引变得越来越大而降低吗?
\n对于 10 亿行或 1000 亿行,就性能而言,好的索引总是优于分区吗?
\n--
\n还有一点最接近我想要受益的:
\n\n\n用例#3——热点。这个解释起来有点复杂。给定以下组合:
\n
\n\xe2\x9a\x88 表的索引太大而无法缓存,但一个分区的索引是可缓存的,并且
\n\xe2\x9a\x88 索引是随机访问的,并且
\n\xe2\x9a\x88 由于更新索引,数据摄取通常会受到 I/O 限制
\n分区可以将所有索引保持在 RAM 中“热”,从而避免大量 I/O。案例 3 的重大胜利:改进缓存以减少 I/O,从而加快操作速度。
\n
“索引缓存”对 InnoDB …
partitioning ×10
sql-server ×6
mysql ×3
columnstore ×2
deadlock ×1
filegroups ×1
index ×1
innodb ×1
join ×1
mariadb ×1
performance ×1
postgresql ×1