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

优化两个简单的MySQL查询-列索引,mysql,query-optimization,key-value,entity-attribute-value,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) un

我是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
我将非常感谢您的帮助。

索引:

数据\u节点\u标记。节点\u id

数据\u节点。源\u id

数据类型

数据\节点\标记。数据\值

数据_node.lat

data_node.lon

引擎将根据基数选择要使用的。您可以做得更少,但这取决于数据的外观

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


DB引擎在每个查询(实际上是每个别名,但不必担心)中每个表只使用一个索引,因此,如果您有两个要查询的字段,您可以使用
复合索引在这两个字段上创建一个复合索引。对于第一个查询,您需要
数据节点(type,id,data\u id)上的索引
数据节点标签(节点id、数据值)


对于第二个查询,您需要在
数据节点(源id、类型、数据lat、数据long、id)
数据节点标记(id、数据值)
(这与第一个查询相同)。

下面是对查询1的建议:

  • 在数据节点标记表的节点id字段上创建索引
  • 将数据节点表中的type字段从enum更改为varchar(10),并在其上创建索引
  • 如果可能,请避免与“%place%”类似,至少左侧部分不应使用变量来使用索引。所以,如果您可以避免它,那么根据您的要求在它上创建一个部分索引,就像前20到20个字符一样
  • 注意:最重要的索引在node_id字段上,因为您要基于它连接两个表。因此,您可以仅通过此索引获得主要的性能差异。


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

    对于id字段的数据节点标签使用外键。 因为您有重复的id字段。您可以使用外键来克服数据的重复

    创建表数据\u节点\u标记(
    id bigint(20)无符号非空自动增量,
    node_id bigint(20)无符号非空,
    data_key varchar(255)非空默认值“”,
    数据值varchar(255)不为空默认值“”,
    主键(id),
    外键(id)引用数据\节点(id)
    )ENGINE=MyISAM默认字符集=utf8

    (这些评论与其说是答案,不如说是警告。)

    对于
    data\u node\u标记
    ,去掉
    id
    ;更改为
    主键(节点id、数据键)
    。即使如此,您最终还是会发现为什么EAV模式很糟糕

    您还将发现lat/lng难以优化的原因

    使用InnoDB,而不是MyISAM


    比如“%place%”
    无法优化(尽管
    比如“place%”
    可以使用索引)。考虑<代码>全文> <代码>。< /P>所有列中的一个索引或每个列的单独索引。这些索引以列定义的顺序定义。每个建议的索引都是一个索引。列
    数据\u id
    不是
    自动增量
    。不幸的是,除了
    id
    之外,所有字段都不是唯一的。但是谢谢你提供剩下的信息。我认为它们可能有用。复合索引通常更好。MyISAM引擎中是否有部分索引?是的,MyISAM中没有阻止创建部分索引的限制…首先,只需在数据\u node\u标记的node\u id字段上创建一个索引并检查性能…进一步检查根据不同条件过滤的数据量后,我们可以最后确定应该创建哪个字段索引…注意,两个查询都会检查WHERE子句中左侧外部联接表中的值,使它们都有效地成为内部联接,并且它们使用聚合器,而不实际聚合任何东西I have not InnoDB,因为MyISAM更适合我的目的(频繁阅读,罕见的修改)。MyISAM引擎中没有外键。但感谢您的尝试!:)不知道…:)您的查询正常(不会显示错误),但外键将被忽略。相反,它将仅为此列创建索引。myisam不支持外键…即使innodb db中的外键也只提供性能,就像您在没有外键的节点id字段上创建索引一样。