SQL分隔大字段以加快查询速度

时间:2018-05-23 11:23:19

标签: mysql sql database database-design

我们说我有一张桌子书:

BOOK_ID INT(6) PK
--------------------
FILE_EXTENSION VARCHAR(5)
TITLE VARCHAR(60)
LANGUAGE VARCHAR(10)
EDITION INT(2)
PUBLISHMENT_OFFICE_ID INT(4)
PUBLISH_YEAR INT(4)
RATING INT(1)
FILE_UPDOAD_DATE DATE
LINK VARCHAR(150)

此表既可用于搜索书籍(例如,通过扩展,出版社,作者(来自其他表格)等)和完全可视化(在页面上打印所有这些字段的书籍)

所以有一个问题:例如,如果我这样做

SELECT BOOK_ID FROM BOOK WHERE FILE_EXTENSION = 'PDF'

这会导致所有大字段(链接,标题和可能计划的BLOB)的加载作为中间结果,还是一旦翻译WHERE子句而没有性能问题就会丢弃任何不必要的字段?

问题导致解决方案:在其他表中使用相同的PK分隔大字段以减慢可视化(因为需要JOIN)但是要加快搜索速度?值得吗?

P.S。这个特定的数据库并不意味着拥有大量的数据,因此我的查询(我希望)不会变得那么慢。但是这个问题是关于通用数据库的。设计(让我们说10 ^ 8个条目)。

P.P.S。请不要将我链接到数据库规范化(我的完整数据库正常化)

2 个答案:

答案 0 :(得分:1)

列存储为其行的一部分。行存储为Page的一部分。如果您需要从一行中选择一列,则需要读取整行,实际上您会读取该行所在的整个页面。这可能是数千行,包括所有列。希望该页面还有您感兴趣的其他行,并且不会浪费读取。

这就是为什么Columnar数据库变得如此受欢迎的分析。它们分别存储列。它们仍然将值存储在Pages中。因此,您可以从磁盘中读取该列的数千行,但在分析中,您可能会对所有或大部分行感兴趣。这样,您可以拥有数百列,但只能读取您要查询的列。


MySQL没有ColumnStore。所以,你需要一个替代方案。


首先,将您的大字段放在一个单独的表格中,您已经提到过。


其次,您可以使用覆盖索引。

如果您索引(file_extension, book_id),则只需阅读索引即可满足查询SELECT book_id FROM book WHERE file_extension = 'pdf'。它永远不需要阅读表本身。 (索引仍然存储为磁盘上的页面,但只存储索引所涉及的列,并且可能是行指针。比表格窄很多。)

虽然这有点笨拙,因为覆盖索引需要涵盖您知道自己感兴趣的列。


在实践中,您的字段足够小,在实际上成为问题之前不能保证这一点。将BLOB存储在单独的表中是明智的。

答案 1 :(得分:0)

"列存储为其行的一部分。" - 是的,不是。所有'小'列一起存储在行中。但是TEXTBLOB,当' big'时,会存储在其他地方。 (这假定为ENGINE=InnoDB。)

SELECT book_id FROM ... WHERE ext = 'PDF'将从INDEX(ext, book_id)中受益。没有这样,查询必然会扫描整个表(100M行?)。使用该索引,它将非常有效。

"在页面上打印所有这些字段的书籍" - 据推测这不包括庞大的柱子?在这种情况下,SELECT book_idSELECT all-these-fields的费用大致相同。这在网页上是合理的 - 如果你不想在一个页面上显示数千本书。这成为了一个糟糕的用户界面"问题,而不是一个低效率的查询"问题。

titlelink可能属于" small"在我上面的讨论中。但是任何BLOBs很可能都是"大"。

是的,可能做"垂直分区"拆分大项目,但这主要是重复InnoDB已经在做的事情。不要打扰。

100M行很好地进入了我们应该讨论这些事情的舞台。到目前为止,我的评论仅涉及表面。为了深入挖掘,我们需要查看真实的架构和一些重要的查询。我希望一些查询很慢。对于100M行,改进一个查询有时会伤害另一个查询。