Mysql 优化5表SQL查询(存储=>;项=>;单词) 桌子

Mysql 优化5表SQL查询(存储=>;项=>;单词) 桌子,mysql,sql,query-optimization,Mysql,Sql,Query Optimization,存储(100000行):id(主键)、名称、lat、lng等 存储项目(9000000行):存储id(fk)、项目id(fk) 项目(200000行):id(主键)、名称 项目单词(1000000行):项目id(fk)、单词id(fk) 单词(50000行):id(主键),单词VARCHAR(255) 注意:所有ID都是整数 ======== 索引 在存储项上创建唯一索引storeitems\u storeid\u itemid\u i(存储项id,项目id) 在item_words(word_

存储(100000行):id(主键)、名称、lat、lng等

存储项目(9000000行):存储id(fk)、项目id(fk)

项目(200000行):id(主键)、名称

项目单词(1000000行):项目id(fk)、单词id(fk)

单词(50000行):id(主键),单词VARCHAR(255)

注意:所有ID都是整数

========

索引 在存储项上创建唯一索引storeitems\u storeid\u itemid\u i(存储项id,项目id)

在item_words(word_id,item_id)上创建唯一索引itemwords_wordid_itemid_i

在单词(word)上创建唯一的索引单词(word)

注意:我更喜欢多列索引(storeitems\u storeid\u itemid\u I和itemwords\u wordid\u itemid\u I),因为:

查询 问题:运行时间为20-120秒(取决于单词)!!! 我希望经过的时间少于5秒!!!有什么想法吗??? ==============

我试过的 我试图通过向查询中添加表来查看执行时间何时增加

1表 2张桌子 3张桌子 4张桌子
我猜是索引或查询/数据库设计的问题。但必须有一种方法让它快速运行。谷歌以某种方式做到了这一点,他们的表要大得多

如果给定了项目id,您没有可以用来查找存储id的索引。如果存储id的基数足够低,它可能会从存储项目\u存储id\u项目id\u i中获得一些好处,但由于您有100000个存储,这可能没有多大用处。您可以尝试在存储项上创建一个索引,首先列出该项的id:

CREATE UNIQUE INDEX storeitems_item_store ON store_items(item_id, store_id);
此外,我不确定在where子句中添加连接条件是否会对性能产生负面影响,但您可以尝试将查询更改为以下内容:

select s.name, s.lat, s.lng, i.name
from words w LEFT JOIN item_words iw ON w.id=iw.word_id
LEFT JOIN items i ON i.id=iw.item_id
LEFT JOIN store_items si ON si.item_id=i.id
LEFT JOIN stores s ON s.id=si.store_id
where w.word='MILK';

如果不知道桌子的确切布局,就很难给出一个好的答案。但是,这些类型的多表联接有陷入困境的趋势。特别是当构成选择表达式的因素之一是动态字符串时

可以尝试从存储过程或其他方法一次返回多个表的结果集,然后在SQL之外加入数据。通过这种方式,我将大规模连接的查询时间从2分钟缩短到4秒。或者使用临时表执行此操作,并在完成后从中返回结果集

首先从单词表中选择,因为这是动态字符串所在的位置。然后,您可以根据该查询返回的数据从其他表中进行选择。

试试这个。
以这种方式重写查询

选择s.name、s.lat、s.lng、i.name
从单词w左连接项目w单词iw ON w.id=iw.word\u id和w.word='MILK'
左连接i.id上的项目i=iw.item\u id
左连接存储\项目si ON si。项目\ id=i.id
在s.id=si.store\u id上左连接存储s

并在(w.id,w.word)上创建索引。

您尝试过分析这些表吗? 这将有助于优化人员选择最佳的执行计划

e、 g:

请参阅:

a)您实际上是在mysql中编写查询来执行FTS->使用像lucene这样的真正FTS

b) 显然,添加9M行联接是性能问题

c) 如何限制该连接(可能是使用当前查询计划完全完成的),如下所示:

SELECT
    s.name, s.lat, s.lng, i.name
FROM
    (SELECT * FROM words WHERE word='MILK') w
INNER JOIN
    item_words iw
ON
    iw.word_id=w.id
INNER JOIN
    items i
ON
    i.id=iw.item_id
INNER JOIN
    store_items si
ON
    si.item_id=i.id
INNER JOIN
    stores s
ON
    s.id=si.store_id;
这背后的逻辑是,不是连接完整的表然后限制结果,而是从限制要连接的表开始,这(如果连接顺序恰好是我编写的),将大大减少工作集和内部查询的运行时间


d) Google不使用mysql进行FTS

考虑取消结构规范化-第一个候选项是100万记录项_单词表-将单词直接放入表中。通过视图创建唯一单词列表可能更容易实现(取决于您需要此数据的频率,而不是提取包含与关键字关联的产品的商店列表)。
其次,创建索引视图(在MySQL中不是一个选项,但在其他商业数据库中肯定是一个选项)。

不,说真的。我们不是来为你工作的。如果你有特定的问题,请随意提问。如果您想查看代码,请转到。如果您有设计问题,请访问。但是不要期望任何像“我需要[东西]”这样的问题会得到回答,请帮我做吧。您可能还想看看-指南和相关主题。word列的数据类型是什么?似乎索引太大,无法放入内存。你真的需要它是唯一的字段还是你可以在部分字段上创建索引?@Bobby me:)@Ivan我不完全确定如果你使用
内部联接而不是笛卡尔积,上的执行计划会有什么不同。@Bobby这是一个关于性能优化的问题。我们这里有很多这样的问题,这一个比大多数其他问题提供了更多的信息。我唯一缺少的是@Ivan已经试图从中获得更多的东西。@Darhazer这个词的索引不是问题,因为像SELECT*FROM word='MILK'这样的简单查询;不到0.5秒。我想查询/数据库设计中的索引有问题…我现在可能在撒谎…:)。。。但是我记得我很久以前尝试过这个,查询优化器基本上把你的选择和他最初的选择变成了大致相同的查询。当然,这取决于SQL的版本和查询优化器的自由度。但正如我所说。。。我可能记错了,所以就躺在这里;)@inquam我认为您在这一点上是正确的-优化器应该这样做-而且可能会这样做,但尝试将其更改一点,看看会发生什么是合理的。我还把他的加入改成了左乔
select count(*)
from words w, item_words iw
where iw.word_id=w.id
and w.word='MILK';

Elapsed time: 0.5-2 sec (depending on word)
select count(*)
from words w, item_words iw, items i
where iw.word_id=w.id
and i.id=iw.item_id
and w.word='MILK';

Elapsed time: 0.5-2 sec (depending on word)
select count(*)
from words w, item_words iw, items i, store_items si
where iw.word_id=w.id
and i.id=iw.item_id
and si.item_id=i.id
and w.word='MILK';

Elapsed time: 20-120 sec (depending on word)
CREATE UNIQUE INDEX storeitems_item_store ON store_items(item_id, store_id);
select s.name, s.lat, s.lng, i.name
from words w LEFT JOIN item_words iw ON w.id=iw.word_id
LEFT JOIN items i ON i.id=iw.item_id
LEFT JOIN store_items si ON si.item_id=i.id
LEFT JOIN stores s ON s.id=si.store_id
where w.word='MILK';
ANALYZE TABLE words
ANALYZE TABLE item_words
ANALYZE TABLE items
ANALYZE TABLE store_items
ANALYZE TABLE stores
SELECT
    s.name, s.lat, s.lng, i.name
FROM
    (SELECT * FROM words WHERE word='MILK') w
INNER JOIN
    item_words iw
ON
    iw.word_id=w.id
INNER JOIN
    items i
ON
    i.id=iw.item_id
INNER JOIN
    store_items si
ON
    si.item_id=i.id
INNER JOIN
    stores s
ON
    s.id=si.store_id;