【问题标题】:SQL Does Insert Order of Rows Matter?SQL 插入行的顺序是否重要?
【发布时间】:2018-07-05 15:56:58
【问题描述】:

我是第一次探索数据仓库的数据库新手。我已经完成了将大量数据从我们的一个生产系统 (MS SQL Server 2012) 复制到我们的数据仓库 (MySQL) 的过程。

我遇到的问题是可用于 ETL 过程的软件/硬件资源不够强大,无法使用单个查询复制较大表中的所有数据(程序会耗尽内存并崩溃) .为了解决这个问题,我通过在表 id 上使用模运算符添加 where 子句将这些表分成 12 个块,因为这既快速又易于编写:

SELECT * FROM table WHERE table.tableID % 12 = 0;
SELECT * FROM table WHERE table.tableID % 12 = 1;
SELECT * FROM table WHERE table.tableID % 12 = 2;
etc.

我现在想知道的是,这是否会影响我的数据仓库相对于原始数据库的性能。在旧数据库中,数据大致按时间顺序插入,显然新数据仓库不会如此。

我对数据库引擎实际存储数据的方式知之甚少,无法知道这是否是一个问题。我在数据仓库中拥有与原始表中相同的所有索引,但我不知道数据库引擎是否真的会根据索引重新排列内存中的数据以加快读取速度。

以这种方式复制和插入数据是否给自己带来了麻烦?

【问题讨论】:

  • 当你可以orderby时为什么重要?
  • @emsimpson92 这是一个关于性能的问题,我猜不是 SQL 本身
  • @connorg98 你是对的。如果插入的顺序与数据在磁盘上的位置直接相关,那么按日期排序/过滤可能需要接触更多的内存块。再说一次,我对这些东西的理解很模糊,对 DB 的底层工作方式知之甚少。
  • 如果表上有聚集索引,它将按该索引排列,正如 Gordon 在下面的答案中指出的那样。因此,像这样划分插入可能会导致由于页面拆分而拥有更多的总页数,但查询性能几乎不会受到影响。

标签: sql indexing sql-insert


【解决方案1】:

这可能不会有什么不同。数据库通常只能在声明(某种类型的)聚集索引时利用表内的排序。如果您声明了一个,则数据将在数据页上排序,而不管插入顺序如何。如果您没有,那么优化器将无法利用排序。

有些类型的查询(特别是exists)的性能可能会受到读取数据时数据到达的实际顺序的影响。但这并不常见。如果表不适合内存,并且您依赖相似的数据共同定位来提高性能,那么您的性能也可能会很差。这通常是一个糟糕的假设,但它可能是某些查询的基础。

在某些情况下,数据排序可能会产生看似正确的结果,但这些是“坏”的 SQL:

  • 没有ORDER BY 子句但期望以特定顺序获得结果的查询。
  • 使用 MySQL 错误(功能)的查询允许在聚合查询的 SELECT 中使用非聚合、非键列。
  • 依赖于没有ORDER BY 子句的GROUP_CONCAT() 中的值排序的查询。

这些都是“坏的”,因为它们取决于观察到的系统行为,而不是记录在案的行为(毫无疑问,我可能遗漏了一些)。

当然,您可以测试您的新系统,看看是否是这种情况。但是先验插入的顺序不是我首先关心的问题。

【讨论】:

  • 在数据仓库上运行需要 50 秒的测试查询在生产数据库上运行不到 1 秒。其他两个可能起作用的因素:1)在 ETL 过程中,我将生产数据库(20180601)中的整数日期转换为数据仓库中的 SQL 日期('2018-06-01'),这可能会慢得多处理在一个 between 子句中? 2) 我们正在对整个数据仓库概念进行原型设计,因此目前数据仓库运行的硬件资源比生产数据库少。
  • 还在我们的测试查询的连接中发现了一个错误,导致返回的行数过多。一旦我解决了这个问题,查询就会及时完成。这似乎证明了@Gordon 的观点,即顺序无关紧要。不过仍然对上面的日期问题感到好奇。
  • @GenuineSmile29 。 . .它并没有“证明”这一点。不过,它确实提供了支持证据。干杯。很高兴它正在奏效。
【解决方案2】:

如果你有相同的索引,数据将或多或少以相同的方式存储,假设你在一个列上有一个哈希索引,这个结构的实现在 MySql DB 和 MySql 服务器中是相似的。问题是 oltp 工作负载与 olap 不同,因此 oltp 的良好索引对于数据仓库来说仍然不是良好的索引,但这取决于您的数据。查看这篇文章以更好地了解 oltp 和 olap 的区别:oltp vs olap。尝试考虑如何减少表基数,假设在您的 oltp 系统中您存储有关销售的信息,并且您有以下内容:

|  DateTime        | Product | QTY |
| ---------------- | --------|-----|
| 2018-03-05 10:50 |  prod1  |  5  |

包含 10^8 条记录的表。也许您只想在日期中存储产品的数量,如下所示:

|    Date    |     Qty     |
|------------|-------------|
| 2018-03-05 |    10000    |

这将减少您表的基数并提高您的应用程序的效率

【讨论】:

  • 感谢您的反馈和有用的文章!
猜你喜欢
  • 1970-01-01
  • 2011-03-10
  • 2017-05-21
  • 2012-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多