MySQL在Where子句中添加列的查询性能



我有一个查询,在WHERE子句中增加了几个列值。我无法在单列中预先计算此添加,因为要使用的列的组合在查询之间有所不同。我的问题是我的桌子很大(数亿行)和表演非常糟糕。

示例表:

+---------+------------+--------+--------+--------+--------+
| tableId | categoryId | value1 | value2 | value3 | value4 |
+---------+------------+--------+--------+--------+--------+
|       1 |          1 |      1 |      0 |      5 |      7 |
|       2 |          1 |      8 |      1 |      7 |      0 |
|       3 |          1 |     10 |      5 |      0 |     20 |
|       4 |          2 |      0 |     15 |      0 |     22 |
|       5 |          2 |     20 |      0 |     11 |      0 |
+---------+------------+--------+--------+--------+--------+

示例查询:

SELECT * FROM myTable WHERE categoryId = 1 AND (value1 + value2 + value3 + value4) > 9;
SELECT * FROM myTable WHERE categoryId = 1 AND (value1 + value3 + value4) > 5;

改善此类查询性能的最佳策略是什么?(编辑:我已经在categoryId上有索引,这无济于事)

是否使用索引帮助进行此类查询?然后,我是否需要为列的所有可能组合创建所有可能的索引?结果索引不是很大吗?

ALTER TABLE myTable
ADD INDEX(categoryId, value1),
ADD INDEX(categoryId, value2),
ADD INDEX(categoryId, value3),
ADD INDEX(categoryId, value4),
ADD INDEX(categoryId, value1, value2),
ADD INDEX(categoryId, value1, value3),
ADD INDEX(categoryId, value1, value4),
etc

或可能创建一个链接表,并用布尔值字段指定使用了哪些列?但这将导致一张数十亿行的桌子,不确定这更好...

+---------+-----------+-----------+-----------+-----------+----------+
| tableId | useValue1 | useValue2 | useValue3 | useValue4 | valueSum |
+---------+-----------+-----------+-----------+-----------+----------+
|       1 |         1 |         1 |         1 |         1 |       13 |
|       1 |         1 |         1 |         1 |         0 |        6 |
|       1 |         1 |         1 |         0 |         0 |        1 |
|       1 |         1 |         1 |         0 |         1 |        8 |
|       1 |         1 |         0 |         1 |         1 |       13 |
|       1 |         1 |         0 |         1 |         0 |        6 |
|       1 |         1 |         0 |         0 |         0 |        1 |
|       1 |         1 |         0 |         0 |         1 |        8 |
|       1 |         0 |         1 |         1 |         1 |       12 |
|       1 |         0 |         1 |         1 |         0 |        5 |
|       1 |         0 |         1 |         0 |         0 |        0 |
|       1 |         0 |         1 |         0 |         1 |        7 |
|       1 |         0 |         0 |         1 |         1 |       12 |
|       1 |         0 |         0 |         1 |         0 |        5 |
|       1 |         0 |         0 |         0 |         1 |        7 |
+---------+-----------+-----------+-----------+-----------+----------+

索引:

ALTER TABLE linkTable INDEX(tableId, useValue1, useValue2, useValue3, useValue4, valueSum);

其他想法?

@e4c5是正确的,这些索引都不会帮助当前查询。您可以首先添加以下索引并在其他条件下更改查询,以便使用这些索引:

ALTER TABLE myTable
ADD INDEX(categoryId, value1),
ADD INDEX(categoryId, value2),
ADD INDEX(categoryId, value3),
ADD INDEX(categoryId, value4);

并更新这样的查询:

SELECT * FROM myTable WHERE categoryId = 1 AND (value1 <= 9) AND (value2 <= 9) AND (value3 <= 9) AND (value4 <= 9) AND (value1 + value2 + value3 + value4) > 9;
SELECT * FROM myTable WHERE categoryId = 1 AND (value1 <= 5) AND (value3 <= 5) AND (value4 <= 5) AND (value1 + value3 + value4) > 5;

其他条件有助于缩小要处理的行的数量。在更多列上添加索引会进一步加快此功能,但我建议先尝试一下。

我必须做一些猜测,直到看到SHOW CREATE TABLE ...

如果有:

tableId INT UNSIGNED AUTO_INCREMENT NOT NULL,
categoryId INT UNSIGNED NOT NULL,
...
PRIMARY KEY(tableId),

然后更改为

tableId INT UNSIGNED AUTO_INCREMENT NOT NULL,  -- same
categoryId INT UNSIGNED NOT NULL,              -- same
...
PRIMARY KEY(categoryId, tableId),  -- different, see Note 1
INDEX(tableId)                     -- different, see Note 2

注1.从categoryId开始的索引(PK)将有助于您提出的查询。此外,通过在PK的开头,它将"聚集"一个SELECT的所有必要行,从而最大程度地减少您的巨大桌子中的I/O。

注意2。是的,可以只有INDEX(...)的CC_6。

另一个提示...因为BIGINT总是8个字节,而INT为4个字节;您真的需要这么大的专栏吗?缩小柱子尺寸将有助于减少I/O,这将大大加快查询。MEDIUMINT UNSIGNED只有3个字节,范围为0..16m;等。

基于我有关整体数据库设计的后续问题的答案,结论是:

  • 我所有的数据类型和索引都是正确的。
  • 我使用枚举列的设计不是很优雅,而是适合基于行的数据库(例如MySQL),并在这种引擎上提供了最佳性能。
  • 为了真正解决此性能问题,我应该使用我的其他问题的评论中所述的更好的设计(在其中汇总数据将在同一列中,但几行)。

您可以将查询放入类别。对于每个类别,您可以保留预先计算的列。您可以根据所需的计算组合从表中选择相关字段。当然,如果您可以对查询进行分类。

相关内容

  • 没有找到相关文章

最新更新