不确定我的MySQL索引策略应该是什么样子

时间:2017-08-24 01:05:01

标签: mysql join indexing subquery

这是我写的一个查询:

SELECT DISTINCT m.*, sm.*, s.*
FROM table_1 m
LEFT JOIN table_2 sm ON m.master_id = sm.master_id
INNER JOIN (
    SELECT s1.*, rn.field1, d.field2, m.field3, dt.field4, gl.field5
    FROM table_3 s1
        LEFT JOIN table_4 rn ON s1.secondary_id = rn.secondary_id
        LEFT JOIN table_5 d  ON s1.trait_id = d.trait_id
        LEFT JOIN table_6 m  ON s1.mix_id = m.mix_id
        LEFT JOIN table_7 dt ON s1.debit_id = dt.debit_id
        LEFT JOIN table_8 gl ON s1.graph_id = gl.graph_id
    WHERE s1.secondary_id = 26
        AND s1.dimension_id = 24
        AND s1.mix_id = 43
) s ON sm.spec_id = s.spec_id
WHERE m.master_id = 1

我正在一张非常小的桌子上测试它(每张桌子只有大约3000-5000条记录),并且从笔记本电脑上的虚拟机内获得可接受的结果(4.8毫秒)。

我的问题/问题是当表变大时,整个数据库不能驻留在内存中?

显然,所有* _id列都有索引(无论是s1表中的主键列还是外键。我在s1.secondary_id, s1.dimension_id, s1.mix_id上都有一个多列索引。

这是否足够,或者是否比我更精通的人知道我是否应该使用不同的索引,或者完全使用不同的策略来进行这种查询(对表1的查询,对表2的连接,以及另一个连接反对子查询) - 这是让我暂停可伸缩性的最后一部分。

任何想法都表示赞赏。

PS - EXPLAIN表示我可能正在使用临时表(我假设来自联接),但除此之外我不确定我在看什么,类型为constrefeq_ref

同样,它现在只需很少量的测试数据就能正常工作。一旦获得生产级别的数据,我就不希望它停止运转。

由于

3 个答案:

答案 0 :(得分:3)

评论:

  • MySQL中from子句中的子查询可能会导致性能下降,因为它们通常都已实现。
  • 子查询的inner join撤消left join,因为on子句要求密钥为非NULL
  • 您应该将数字列与数字比较字符串。你可能不想要单引号。
  • 明确要求table_3(secondary_id, dimension_id, mix_id)上的索引(其他列可能在此之后有用)。

答案 1 :(得分:0)

就像你提到的那样,你的查询将适用于较少数量的记录。 但是一旦你的数据库开始获得数百万(或数十万)的记录,你的查询就会变慢。

您可以在开始时采取预防措施,以便查询不会变慢:

  1. 将查询分成多个查询:这样您的数据库就会这样 也不会耗尽内存。

  2. 检查query execution plan 查看您的查询是否始终使用索引。它还会告诉您在各种连接操作中使用了多少时间。以及DB为优化您的查询而采取的步骤。

  3. 当数据被送入表中时,表和索引空间一直处于碎片状态。做常规去碎片

  4. 有一点可以肯定的是,Relational数据库不是为水平scaling而设计的,但是它们的垂直扩展非常好,因此安装额外的硬件(额外的内存,CPU)也有帮助

答案 2 :(得分:0)

  • 除非右边的表格是可选的,否则请勿使用LEFT
  • s1上有一个3列'复合'索引。
  • 请提供EXPLAIN SELECT以便我们更好地回答您的问题。我们需要看的不仅仅是它使用临时表。 也许 Explain将提供足够的信息来回答您的可扩展性问题。
  • 不要将查询分解为多个查询 - 除非你真的比优化器更聪明。
  • 不要使用OPTIMIZE TABLE;在InnoDB表上不值得努力。 BTree是自我整理(在某种程度上)。
  • MySQL不会在连接中使用多个CPU。
  • 更多RAM有助于某些用例。
  • DISTINCT(通常)需要临时表和数据的额外传递。由于您正在执行SELECT *,因此您需要进行重复数据删除的唯一方法是在表中实际存在重复项。这似乎不太可能。
  • varchar = numeric-constant是唯一遇到麻烦的组合。常用的int = 'number'可以优化OK。

<强>解释

  • 请注意EXPLAINs中的“行”列。它们都是小数字。
  • 注意'Primary'和'eq-ref'。那些(通常)非常好的东西。
  • 因此,暂时,我预测查询仍然会快速运行,即使表太大而无法缓存。这是因为每个表中只有几行(某些表中只有一行)需要触及。如果太大,没有明显的表扫描或其他会非常昂贵的东西。