如何使用 where 条件的多种组合优化 MySQL 查询?

How to optimize MySQL queries with many combinations of where conditions?

我有一个像这样的 MySQL table,我想创建索引来快速查询 table 运行。难的是where条件的可能组合有很多,而且table的大小很大(大约6M行)。

Table name: items    

id: PKEY
item_id: int (the id of items)
category_1: int
category_2: int
.
.
.
category_10: int
release_date: date
sort_score: decimal

item_id 不是唯一的,因为一个项目可以有多个 category_x .

对此 table 的查询示例是:

SELECT DISTINCT(item_id) FROM items WHERE category_1 IN (1, 2) AND category_5 IN (3, 4), AND release_date > '2019-01-01' ORDER BY sort_score

另一个查询可能是:

SELECT DISTINCT(item_id) FROM items WHERE category_3 IN (1, 2) AND category_4 IN (3, 4), AND category_8 IN (5) ORDER BY sort_score

如果我要优化所有where条件的组合,是不是需要做大量的列组合的复合索引? (喜欢 ADD INDEX idx1_3_5(category_1, category_3, category_5)

或者创建10个table的category_1~10的数据,并在查询中执行很多INNER JOIN是否好?

或者,这种查询在MySQL中很难优化,我是否应该使用其他中间件,例如Elasticsearch?

好吧,文件(它不是 table)根本没有规范化。因此,字段组合上的任何索引都不会帮助查询。

其次,MySQL (a) 不符合 SQL 要求,并且 (b) 它没有服务器架构或其中的功能。

  • 这样的一个统计信息,是真正的Query Optimiser使用的,商业SQL平台都有。您在评论中提出的 "single index" 问题不适用。

因此,虽然我们可以修复 table 等问题,但您可能永远无法从免费软件中获得所需的性能。

  • 例如。在商业世界中,600 万行算不了什么,当我们达到 10 亿行时,我们会担心。

  • 例如。统计是自动的,我们只需要在必要时调整它:非规范化 table 或数十亿行。

Or ... should I use other middlewares , such as Elasticsearch ?

这取决于使用正版SQL vs MySQL,以及中间件。

  • 如果您修复文件并创建一组关系 table,则查询将非常简单且快速。它不证明中间件搜索引擎(在客户端系统上构建数据立方体)是合理的。

  • 如果它们在 MySQL 上速度不快,那么第一个建议是获取商业 SQL 平台而不是免费软件。

  • 最后的选择,也是最后的选择,就是坚持使用免费软件并添加一个大胖子中间件搜索引擎来补偿。

Or is it good to create 10 tables which have data of category_1~10, and execute many INNER JOIN in the queries?

是的。 JOIN 在 SQL 中很普通。与流行的神话相反,规范化数据库,这意味着比非规范化数据库多 tables,导致更少的 JOIN,而不是更多的 JOIN。

所以,是的,标准化那个野兽。十 tables 是开始的感知,仍然完全没有归一化。以下每一项 table 将是朝着规范化方向迈出的一步:

  1. 项目
    Item_id 将是独一无二的。

  2. 类别
    这不是 category-1,等等,而是 category_1 中的每个值,等等。您不能在单个列中有多个值,它会破坏 1NF。这些值将是 (a) 原子的,和 (b) 唯一的。 关系模型 要求行是唯一的。

  3. category_1等在Item中的含义没有给出。 (如果你提供一些示例数据,我可以提高数据模型的准确性。)显然不是 [2].
    .
    如果它是用户选择或投票的优先级 (1..10) 或类似的东西,则此 table 将是一个 table,它提供[之间的多对多关系=14=] 和 Category,每行有一个 Priority
    .
    让我们称之为民意调查。相关的谓词类似于:

    Each Poll is 1 Item
    Each Poll is 1 Priority
    Each Poll is 1 Category
    
  4. 同样,sort_score也不解释。如果它看起来很像,那么您将不需要它。因为它是一个派生值。你应该即时计算:一旦 tables 被归一化,计算它所需的 SQL 是直截了当的。不是每 5 分钟或每 10 秒计算和存储一次。

关系模型

以上保持只回答你问题的范围,没有指出你文件中的难点。注意 Relational Database 标记,本节处理关系错误。

  1. Record ID 字段(item_idcategory_id 是你的)在 关系模型 中被禁止。它是指向记录的物理指针,这显然是 RM 克服的问题,如果希望获得 [=105= 的好处,则必须克服这一点]RM,比如方便查询,简单明了SQL代码。

    相反,Record ID 始终是一个额外的列和一个额外的索引,并且导航所需的 SQL 代码很快变得复杂(和错误)。你将对代码有足够的困难,我怀疑你会想要增加的复杂性。

    因此,删除 Record ID 字段。

  2. 关系模型 要求键为 "made up from the data"。这意味着用户使用的逻辑行中的内容。通常,他们确切地知道是什么标识了他们的数据,例如简称。

    • 不是系统制造的,比如RecordID字段是GUIDAUTOINCREMENT,用户看不到。这些字段是指向记录的物理指针,而不是指向逻辑行的键。这些字段是关系之前的、DBMS 之前的、1960 年代的记录归档系统,正是 RM 所取代的东西。但它们被大力宣传和营销为“关系。

关系数据模型 • 初始

看起来像这样。

  • 我所有的数据模型都在 IDEF1X 中呈现,这是自 1993 年以来的关系数据库建模标准

  • 我的IDEF1X Introduction是初学者必读的

关系数据模型 • 改进

已知三元关系(又名三向 JOIN)是一个问题,表明需要进一步规范化。 Codd 教导每个三元关系都可以简化为两个二元关系。

在您的情况下,也许一个项目具有某些类别,而不是全部类别。上面实现了允许每个项目的所有类别的项目轮询,这是三元关系中的典型错误,这就是它需要进一步规范化的原因。这也是每个 RFS 文件中的经典错误。

因此,更正后的模型是首先将每个项目的类别建立为 ItemCategory,即您的 "item can have several numbers of category_x"。然后允许对该受约束的 ItemCategory 进行投票。请注意,这种级别的限制数据在 1960 年代的记录归档系统中是不可能的,其中 "key" 是一个捏造的 id 字段:

Each ItemCategory is 1 Item
Each ItemCategory is 1 Category
Each Poll is 1 Priority
Each Poll is 1 ItemCategory
  • 您的索引现在简单明了,不需要额外的索引。

  • 同样,您的查询代码现在将变得简单明了,并且更不容易出现错误。

  • 请确保您了解子查询。投票 table 支持可能需要的任何类型的旋转。


针对这样的 table 优化此类查询很麻烦。将类别移至其他 table 只会使速度变慢。

这是部分解决方案...确定可能要用

测试的类别
  1. =
  2. IN
  3. 一个范围,比如你的例子release_date > '2019-01-01'

然后设计一些具有 3-4 列的索引(可能不超过十几个)。这些列应该是经常一起测试的列。根据上面的列表对索引中的列进行排序。有多个 = 列(第一个)是很好的,但不要包含超过一个 'range' 个(最后一个)。

请记住,WHERE 中的测试顺序并不重要,但 INDEX 中的列顺序很重要。