优化两个简单的MySQL查询 - 列索引

时间:2016-01-28 12:01:43

标签: mysql query-optimization key-value entity-attribute-value

我是MySQL查询优化的新手,需要有关如何针对两个查询优化数据库的建议 - 我应该设置哪些索引以及在哪里建立。下面是数据库结构和查询。

CREATE TABLE `data_node` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `type` enum('node','place') DEFAULT NULL,
  `name` varchar(255) DEFAULT '',
  `source_id` bigint(20) unsigned DEFAULT NULL,
  `data_id` bigint(20) unsigned NOT NULL,
  `data_lat` decimal(8,6) NOT NULL,
  `data_lon` decimal(9,6) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `data_node_tag` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `node_id` bigint(20) unsigned NOT NULL,
  `data_key` varchar(255) NOT NULL DEFAULT '',
  `data_value` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

首先查询:

SELECT *
FROM data_node n
LEFT JOIN data_node_tag nt ON nt.node_id = n.id
WHERE n.type = "place"
  AND nt.data_value LIKE "%place%"
GROUP BY n.data_id LIMIT 100

第二次查询:

SELECT *
FROM data_node n
LEFT JOIN data_node_tag nt ON nt.node_id = n.id
WHERE n.source_id = 123
  AND n.type = "node"
  AND nt.data_value = "cafe"
  AND (n.data_lat BETWEEN 1.000000 AND 2.000000)
  AND (n.data_lon BETWEEN 3.000000 AND 4.000000)
GROUP BY n.data_id LIMIT 1000

我将非常感谢你的帮助。

5 个答案:

答案 0 :(得分:0)

索引:

  
    

data_node_tag.node_id

         

data_node.source_id

         

data_node.type

         

data_node_tag.data_value

         

data_node.lat

         

data_node.lon。

  

引擎将根据基数选择要使用的引擎。你可以做得更少,但这取决于你的数据是什么样的。

其次,您应该索引where子句中使用的任何字段。 唯一的任何字段都应具有唯一索引。您还可以在多个字段上创建复合索引,但从每个字段的索引开始。

数据库引擎每个查询每个表只能使用1个索引(实际上是每个别名,但不要担心)所以如果你有2个字段要查询,你可以在两个字段上创建一个复合索引。那些composite index

的人

答案 1 :(得分:0)

对于第一个查询,您需要data_node(type, id, data_id)data_node_tag(node_id, data_value)上的索引。

对于第二个查询,您需要data_node(source_id, type, data_lat, data_long, id)data_node_tag(id, data_value)上的索引(这与第一个查询相同)。

答案 2 :(得分:0)

以下是对query1的建议:

  1. 在data_node_tag表的node_id字段上创建索引。
  2. 在data_node表中将类型字段从enum更改为varchar(10)并在其上创建索引。
  3. 如果可能的话避免使用'%place%',至少左边的部分不应该变量来使用索引。因此,如果您可以避免它,那么根据您的要求在其上创建一个部分索引,例如前20到20个字符。
  4. 注意:最重要的索引在node_id字段上,因为您要根据它连接两个表。因此,您只能通过此索引获得主要的性能差异。

    进一步优化查询1& 2它将取决于根据不同条件过滤的数据量。

答案 3 :(得分:0)

data_node_tag 表的外键用于 id 字段。 由于您有重复的 id 字段。您可以使用外键来克服重复数据。

CREATE TABLE data_node_tag ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, node_id bigint(20) unsigned NOT NULL, data_key varchar(255) NOT NULL DEFAULT '', data_value varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (id), FOREIGN KEY (id) REFERENCES data_node(id) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

答案 4 :(得分:0)

(这些评论更多的是警告而不是答案。)

data_node_tag,摆脱id;更改为PRIMARY KEY(node_id, data_key)。即便如此,你最终还是会发现为什么EAV架构很糟糕。

您还将了解为什么lat / lng难以优化。

使用InnoDB,而不是MyISAM。

无法优化

LIKE "%place%"(尽管LIKE "place%" 可以使用索引)。考虑FULLTEXT