使用索引优化mysql查询

发布于 2024-12-22 23:55:32 字数 853 浏览 2 评论 0原文

我对这个查询有一个问题:

SELECT DISTINCT s.city, pc.start, pc.end 
FROM postal_codes pc LEFT JOIN suspects s ON (s.postalcode BETWEEN pc.start AND      pc.end) 
WHERE pc.user_id = "username" 
ORDER BY pc.start

可疑表有大约 340 000 个条目,在邮政编码上有一个索引,我有几个用户,但是这个单独的查询大约需要 0.5 秒,当我用解释运行这个 SQL 时,我得到这样的结果:http://my.jetscreenshot.com/7536/20111225-myhj-41kb.jpg - 这些 NULL 是否意味着查询未使用索引?该索引是一个 BTREE,所以我认为它应该运行得更快一点。

你能帮我解决这个问题吗?如果需要任何其他信息,请告诉我。

编辑:我在 Suspects.postalcode、postal_codes.start、postal_codes.end、postal_codes.user_id 上有索引。

基本上我想要实现的目标是:我有一个表,其中每个用户 ID 都分配了多个邮政编码范围,所以它看起来像:

user_id | start | end

比我有一个嫌疑人表,其中每个嫌疑人都有一个地址(其中包含邮政编码),所以在这个查询我试图获取邮政编码范围 - 开始和结束以及该范围内的城市名称。

希望这有帮助。

I have a problem with this query:

SELECT DISTINCT s.city, pc.start, pc.end 
FROM postal_codes pc LEFT JOIN suspects s ON (s.postalcode BETWEEN pc.start AND      pc.end) 
WHERE pc.user_id = "username" 
ORDER BY pc.start

Suspect table has about 340 000 entries, there is a index on postalcode, I have several users, but this individual query takes about 0.5s, when I run this SQL with explain, I get something like this: http://my.jetscreenshot.com/7536/20111225-myhj-41kb.jpg - does these NULLs mean that the query isn't using index? The index is a BTREE so I think this should run a little faster.

Can you please help me with this? If there are any other informations needed just let me know.

Edit: I have indexes on suspects.postalcode, postal_codes.start, postal_codes.end, postal_codes.user_id.

Basically what I'm trying to achieve: I have a table where each user ID has multiple postalcode ranges assigned, so it looks like:

user_id | start | end

Than I have a table of suspects where each suspect has an address (which contains a postalcode), so in this query I'm trying to get postalcode range - start and end and also name of the city in this range.

Hope this helps.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

合久必婚 2024-12-29 23:55:32

每当使用左连接时,都会选取第一个表的所有记录,而不是基于索引进行选择。我建议使用内部联接。就像下面的查询一样。

select distinct 
  s.city, 
  pc.start, 
  pc.end 
from postal_codes pc, suspect s 
where 
  s.postalcode between (select pc1.start, pc1.end from postal_code pc1 where pc1.user_id = "username" ) 
  and pc.user_id = "username"
order by pc.start

Whenever left join is used all the records of the first table are picked up rather than the selection on the basis of index. I would suggest to using an inner join. Something like in the below query.

select distinct 
  s.city, 
  pc.start, 
  pc.end 
from postal_codes pc, suspect s 
where 
  s.postalcode between (select pc1.start, pc1.end from postal_code pc1 where pc1.user_id = "username" ) 
  and pc.user_id = "username"
order by pc.start
神经暖 2024-12-29 23:55:32

它仅使用一个索引,而不是连接中涉及的字段。尝试为开始和结束字段创建索引,或使用 >= 和 <= 而不是 BETWEEN

It's using only one index, and not for the fields involved in the join. Try creating an index for the start and end fields, or using >= and <= instead of BETWEEN

拧巴小姐 2024-12-29 23:55:32

不是100%确定,但是可能是相关的:

有时 MySQL 不使用索引,即使有可用的索引。发生这种情况的一种情况是优化器估计使用索引将需要 MySQL 访问表中很大比例的行。 (在这种情况下,表扫描可能会更快,因为它需要更少的查找。)但是,如果这样的查询使用 LIMIT 只检索某些行,MySQL 无论如何都会使用索引,因为它可以更快地找到结果中返回的几行。

因此,尝试使用 LIMIT 进行测试,如果它使用索引,那么您就找到了原因。

Not 100% sure, but this might be relevant:

Sometimes MySQL does not use an index, even if one is available. One circumstance under which this occurs is when the optimizer estimates that using the index would require MySQL to access a very large percentage of the rows in the table. (In this case, a table scan is likely to be much faster because it requires fewer seeks.) However, if such a query uses LIMIT to retrieve only some of the rows, MySQL uses an index anyway, because it can much more quickly find the few rows to return in the result.

So try testing with LIMIT, and if it uses the index then, you found your cause.

腹黑女流氓 2024-12-29 23:55:32

我不得不说我对你的表命名约定有点困惑,我希望“可疑”表有一个 user_id 而不是 postal_code,但你必须有你的理由。如果您要保持此查询不变,则可以在 postal_code (star,end) 上添加索引以避免完整的表扫描。

I have to say I'm a little confused by your table naming convention, I would expect the "suspect" table to have a user_id not the postal_code, but you must have your reasons. If you were to leave this query as it is, you can add an index on postal_code (star,end) to avoid the complete table scan.

攀登最高峰 2024-12-29 23:55:32

我认为您可以像下面这样重构您的查询,

SELECT DISTINCT s.city, pc1.start, pc1.end FROM 
(SELECT pc.start and pc.end from postal_codes pc where pc.user_id = "username") as pc1,    Suspect s
WHERE s.postalcode BETWEEN pc1.start, pc1.end ORDER BY pc1.start

由于左连接和您的之间条件,您的查询没有选取 s 表上的索引。表中拥有索引并不一定意味着它将在所有查询中使用。

I think you can restructure your query like following,

SELECT DISTINCT s.city, pc1.start, pc1.end FROM 
(SELECT pc.start and pc.end from postal_codes pc where pc.user_id = "username") as pc1,    Suspect s
WHERE s.postalcode BETWEEN pc1.start, pc1.end ORDER BY pc1.start

your query is not picking up the index on s table because of left join and your between condition. Having an Index in your table doesn't necessarily mean that it will be used in all the queries.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文