【问题标题】:What should I index mysql?我应该索引什么mysql?
【发布时间】:2015-03-09 07:00:55
【问题描述】:

我希望加快此查询的速度。我目前在

上有一个索引
users_score.appID
app_names.name

SELECT users_scores.username, users_scores.avatar, users_scores.score
FROM users_scores
RIGHT JOIN app_names ON app_names.id = users_scores.appID
WHERE app_names.name =  "testapp1"
ORDER BY users_scores.score DESC 
LIMIT 0 , 30

【问题讨论】:

  • 基本上出现在 JOIN 或 WHERE 或 ORDER BY 子句中的每一列。
  • 在您的问题中包含EXPLAIN SELECT users_scores.username, users_scores.avatar, users_scores.score FROM users_scores RIGHT JOIN app_names ON app_names.id = users_scores.appID WHERE app_names.name = "testapp1" ORDER BY users_scores.score DESC 的结果,您最终将学习如何为 any 查询解决这个问题...
  • 除了一般查询优化之外,我要注意的一件事是,当内部连接似乎足够时,表 app_names 正在被正确连接 - 不仅如此,连接根本不需要如果您的应用程序知道它需要为其查找分数的 app_names.id - 那么您只需要 users_scores.appID 上的索引
  • @PaulDixon 我只是根据分析速度测试使用正确的连接。我使用的是内部联接,但查询的运行时间是右联接的两倍。此外,应用程序不会知道它需要使用什么 ID,它会通过使用应用程序名称查看该表来找到它。
  • 好的,我现在将其设置为内部连接。不知道配置文件的内容是什么,但昨晚它的运行速度几乎是内部与右侧的两倍。今天很火爆。

标签: mysql performance indexing


【解决方案1】:

您的主键上有索引吗? (users_score.id,或任何您命名的名称)。如果没有,键应该总是被索引......事实上,它们是索引。 app_names.id 也应该是主键/索引。

appID 是一个很好的索引,但是我看到您通过名称搜索应用程序。如果 MySQL 不必对 WHERE 子句执行字符串比较,它会更快。搜索 AppID 会更有效率。鉴于应用名称已知('testapp1'),您可以在搜索之前执行内部查询以确定 ID,如下所示。

WHERE app_names.id = (SELECT id FROM app_names WHERE app_names.name = "testapp1")

【讨论】:

  • 这就是我喜欢 stackoverflow 的地方。我永远不会想到运行 2 个查询会比 1 个更快。将其放入查询后,它从 1-1.5 秒变为 0.000112 秒。
  • 哇!我预计会有改进,但这太棒了!
【解决方案2】:

你不应该使用RIGHT JOIN。任何RIGHT JOIN 都可以而且应该写成LEFT JOIN

无论如何,您的WHERE 子句会自动将查询转换为INNER JOIN

SELECT users_scores.username, users_scores.avatar, users_scores.score
FROM app_names
INNER JOIN users_scores
ON users_scores.appID = app_names.id
WHERE app_names.name = 'testapp1'
ORDER BY users_scores.score DESC
LIMIT 30

由于您没有从 app_names 返回任何数据,因此您可以使用子查询完全摆脱 JOIN:

SELECT username, avatar, score
FROM users_scores
WHERE appID = (SELECT id FROM app_names WHERE name = 'testapp1' LIMIT 1)
ORDER BY score DESC
LIMIT 30

MySQL 首先执行不相关的子查询,因此 MySQL 可以使用 app_names 表上的索引进行搜索,然后能够使用 users_scores 上的索引进行搜索和排序。

为获得最佳读取性能,请在 user_scores(appID, score) 上添加多列索引以满足搜索和排序,或者使用更大的覆盖索引user_scores(appID, score, username, avatar)

【讨论】:

  • RIGHT JOIN 只是一个翻转的 LEFT JOIN -- 为什么它“不好”?
  • 它不常用(也没有广泛支持)。 MySQL docs 说:RIGHT JOIN 的工作方式类似于 LEFT JOIN。为了保持代码跨数据库的可移植性,建议您使用 LEFT JOIN 而不是 RIGHT JOIN。
【解决方案3】:
SELECT  users_scores.username, users_scores.avatar, users_scores.score
    FROM  users_scores
    RIGHT JOIN app_names                 -- Probably forces app_names to be first
              ON app_names.id
                  = users_scores.appID   -- users_scores second; Step 1
    WHERE  app_names.name = "testapp1"   -- app_names first; Step 1
    ORDER BY  users_scores.score DESC
    LIMIT  0 , 30

app_names 需要INDEX(name)

users_scores 需要INDEX(appID)

即使您删除了RIGHT(可能是噪音),优化器也会首先选择app_names,因为WHERE 子句仅提及app_names

所有这些以及更多内容都可以在我的博客Creating an Index from a SELECT 中找到。

【讨论】:

  • 又因为……降级了?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-01
  • 2016-08-25
相关资源
最近更新 更多