优化两个简单的MySQL查询-列索引
我是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
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字段上创建索引一样。