我正在寻求有关如何考虑表所需的最少索引数量的指导,在该表中,您可以在同一列列上执行不同的查询组合。理想情况下,您的答案将从这个具体示例中抽象出一些经验法则(如果可能的话)。
这个项目符号列表代表了我桌面上常见的三种不同查询条件:
注意:user_id(int),race_type(varchar),recordable_id(int),recordable_type(varchar),active(boolean)
我可以为每个索引创建单独的多列索引,但是你的DB性能专家可能会以不同的方式处理它。
如果我需要提供更多信息以获得最佳答案,请告诉我们。
答案 0 :(得分:8)
如果您的条件是分层的(如您的示例中所示),则可以使用组合索引。 DBMS在同时处理多个索引时遇到问题。尽管有可能并且他们试图在这种情况下做到最好。
这不会改变您应该尝试为某个where子句设置特定索引的事实。如果更多的WHERE'索引可以组合成一个索引,然后释放一些空间和CPU周期。
让我们开始为每个WHERE指定一个索引:
index1 (race_type, recordable_type, active)
index2 (race_type, recordable_id, recordable_type, active)
index3 (user_id, race_type, recordable_id, recordable_type, active)
通常,您可以通过提升基数来优化订单。基数是列在数据集中的可能值的数量。在您的示例中,active
是一个布尔值。 (请注意,boolean
只能包含两个值这一事实并不重要。如果您知道它只有两个值,则可能是int
:0和1 )。
active
字段的低基数意味着只需一次查找,我们就可以消除一半可能的记录(当然,这取决于您的数据集)。在此步骤之后,您的第一个索引将如下所示:
index1 (active, race_type, recordable_type)
除了基数之外,您还应该注意字段之间的任何逻辑层次结构。在不确切知道这些名称的含义的情况下,我猜测某些种族类型将拥有自己的可记录。 - 这当然不会消除可录制多种种族使用的可能性,但你必须选择一个订单,这似乎更合乎逻辑。 - 因此我们将使用race_type
,recordable_type
订单。
现在让我们来看看第二个指数。您在此处介绍了recordable_id
。在不知道您的数据集的情况下,我可以放心地假设recordable_id的基数将比recordable_type更高。换句话说,ID会比类型更多。我还怀疑类型和id之间的层次结构(闻起来像一对多)。所以让我们把它放在类似的类型之后:
index2 (active, race_type, recordable_type, recordable_id)
现在是时候关注另一个重要角度了。当修改您的数据库时,索引在您的硬盘上有自己的成本(实际上是免费的)和CPU周期。可以从左到右使用任何索引的子集。 index2
基本上包含index1
,因为它是index1 + recordable_id
,所以你可以摆脱它并最终得到一个。
来到user_id
。作为ID字段,它表示高基数(许多可能的值),但请注意,不是规则,"基数越高,后面的字段将是"。我们宁愿使用基数作为信标来帮助发现字段之间的层次结构关系。 (并缩小索引大小)。
user_id
是否向个别参赛者指出我们正在查看的数据(多种可能性)?或者是上传数据的客户(极少数可能性)?这很难说。你可以将它附加到我们现有的index2
,你最终会得到一个可以在所有三个场景中使用的索引:
search_index (active, race_type, recordable_type, recordable_id, user_id)
...或者它可能值得为此scanario提供第二个索引...
您的问题很特殊,因为您只在where子句中使用=
。如果您有AND (race_type = 1 OR race_type=8)
之类的内容,还有很多其他注意事项,更不用说>
或<
了。此外,如果您使用ORDER BY
,可以将其考虑在您使用的索引中。
答案 1 :(得分:3)
第一步是对正在考虑优化的查询使用EXPLAIN
。 MySQL explain将返回有关哪些索引将用于完成查询的重要信息,并将帮助您优化查询。
根据我的经验,我看到表格采用了任意数量的复合索引排列,它实际上取决于您的应用程序以及您将发出最多的查询。
您还应该考虑将varchar列更改为链接到查找表的ID。它会为您的数据库添加一些额外的架构,但您会获得以下好处:
如果您需要更改列的值,则只需更改一行,即数千行。
您考虑索引的所有列都是数字,本质上比varchars更快,并且在达到最大索引长度限制之前会产生更多开销。
答案 2 :(得分:2)
IMHO
alter table your_table
add index ( race_type, recordable_type, active, user_id, recordable_id);
// watch-out the max length allowed for an index
常见的列为race_type, recordable_type, active
,
我认为通过构建索引,所有5列都适合所有搜索模式。
如果提案无效,请告诉我
答案 3 :(得分:1)
在您的情况下,正确的索引是任何顺序的 user_id + race_type + recordable_id + recordable_type + active 。那很简单。你问过一般方法吗?在这里。
了解索引非常重要。 theem很复杂,所以我的回答很大。我建议阅读我的答案和问题,而不是docs。
where,order和group by中使用的所有列都应具有索引。 Mysql使用二叉树进行索引。这意味着,索引可以从左到右部分地使用而没有间隙。例如。我们在(a,b)上有复合指数。所以:WHERE a = 1 AND b = 1
- 使用完整索引,WHERE a = 1
- 使用索引的一半 - 二叉树索引可以从左边部分使用,WHERE b = 1
- 使用fullscan(不能使用索引), WHERE (a = 0 OR a = 1) AND b = 1
- 使用fullscan(mysql不支持多个搜索分支)。
有些查询根本无法使用索引。例如。带有“OR”语句的查询(二进制树索引是后续的)。或col LIKE'%...%' - 二进制索引只能从左侧部分使用。
应用正确索引的Algorythm:获取您在“WHERE”中使用的所有唯一列名。从查询中出现的顺序获取订单和分组中的所有唯一列名称,并添加到“WHERE”中的字段(从右侧添加)。比缩小索引,所以它们仍然可以被mysql使用。
您的查询中没有任何订单,但订单也需要索引。所以我让你的例子更复杂一点:
WHERE user_id =? AND race_type =? AND recordable_id =? AND recordable_type =? AND active =?按日期排序ASC
来自“WHERE”的索引:“race_type + recordable_type + active”,“race_type + recordble_id + recordable_type + active”和“user_id + race_type + recordable_id + recordable_type + active”。
从排序中添加索引:
缩小索引:
请参阅索引#1包含在索引#2中,因此抛弃索引#1。最后我们有两个索引:
不要忘记按更新和删除查询中使用的algorythm列进行索引。
答案 4 :(得分:1)
Mysql使用最左边的索引,这意味着,如果索引是复杂的(包含多于一列)查询在索引列列表中从左到右遍历索引,如果有void(查询的where或join语句没有将不再使用其他索引列)
快速提示,对于可以编写查询的可能值很少的字段,它会覆盖所有可能的值,这意味着仍然可以使用更多的索引列(例如,where(active = 0或active = 1)和...)
答案 5 :(得分:0)
您在WHERE条件中有以下字段:user_id,race_type,recordable_id,recordable_type和active。其中一些可能会重复指定的条件。
我按照以下方式订购了它们:
* WHERE race_type = ? AND recordable_type = ? AND active = ?
* WHERE race_type = ? AND recordable_type = ? AND active = ? AND recordable_id = ?
* WHERE race_type = ? AND recordable_type = ? AND active = ? AND recordable_id = ? AND user_id = ?
它允许我们创建一个复合索引:
ALTER TABLE table_name
ADD INDEX IX_table_name (race_type, recordable_type, active, recordable_id, user_id);
如果表有其他索引或主键,请添加USE INDEX子句以使用命名索引:
SELECT * FROM table_name USE INDEX IX_table_name
WHERE
race_type = ? AND recordable_type = ? AND active = ? AND recordable_id = ? AND user_id = ?