I have the following query:
SELECT region.id, region.world_id, min_x, min_y, min_z, max_x, max_y, max_z, version, mint_version
FROM minecraft_worldguard.region
LEFT JOIN minecraft_worldguard.region_cuboid
ON region.id = region_cuboid.region_id
AND region.world_id = region_cuboid.world_id
LEFT JOIN minecraft_srvr.lot_version
ON id=lot
WHERE region.world_id = 10
AND region_cuboid.world_id=10;
The Mysql slow query log tells me that it takes more than 5 seconds to execute, returns 2300 rows but examines 15'404'545 rows to return it.
The three tables each have bout 6500 rows only with unique keys on the id and lot fields as well as keys on the world_id fields. I tried to minimize the amount of rows examined by filtering both cuboid and world by their ID and the double WHERE on world_id, but it did not seem to help.
Any idea how I can optimize this query?
Here is the sqlfiddle with the indexes as of current status.
答案 0 :(得分:1)
You have joined the two tables "minecraft_worldguard.region" and "minecraft_worldguard.region_cuboid", on region.world_id and region_cuboid.world_id. So WHERE clause wouldn't require two conditions.
The two columns in the WHERE clause have been equated in the JOIN condition, hence you wouldn't require checking both the conditions in the WHERE clause. Remove one of them in the WHERE clause and add an index on the column that is remaining on the WHERE condition.
In your example, leave the WHERE clause as below: WHERE region.world_id = 10
and add an index on the region.world_id column, that would improve the performance a bit.
NOTE: observe that I am suggesting you to discard "AND region_cuboid.world_id=10;" part of the WHERE clause.
Hope that helps.
答案 1 :(得分:1)
在这种情况下,MySQL无法使用索引,因为连接的字段具有不同的数据类型:
`lot` varchar(20) COLLATE utf8_unicode_ci NOT NULL
`id` varchar(128) COLLATE utf8_bin NOT NULL
如果您将此字段的类型更改为常规类型(例如,region.id
到utf8_unicode_ci
),则MySQL使用主键(fiddle)。
根据docs:
不同列的比较(将字符串列与a。比较 例如,时间或数字列可能会阻止使用索引 如果没有转换,则无法直接比较值。
答案 2 :(得分:1)
首先,在编写具有多个表的查询时,习惯于对表进行“别名”引用是一件非常好的事情,因此您不必重新键入整个长名称。此外,确定列来自哪些表是一个非常好的主意,以便用户更好地了解哪些表还可以帮助提高性能(例如建议覆盖索引)。
也就是说,我已经在您的原始查询中应用了别名,但是根据相应的列AM GUESSING表格,但您显然可以快速识别并进行调整。
SELECT
R.id,
R.world_id,
RC.min_x,
RC.min_y,
RC.min_z,
RC.max_x,
RC.max_y,
RC.max_z,
LV.version,
LV.mint_version
FROM
minecraft_worldguard.region R
LEFT JOIN minecraft_worldguard.region_cuboid RC
ON R.id = RC.region_id
AND R.world_id = RC.world_id
LEFT JOIN minecraft_srvr.lot_version LV
ON R.id = LV.lot
WHERE
R.world_id = 10
我还从where子句中删除了你的“region_cuboid.world_id = 10”,因为基于区域AND世界的JOIN子句是多余的。
对于索引的建议,如果我对列有适当的别名引用,我会建议在区域表上的覆盖索引 (world_id,id)。第一个位置的“World_id”快速限定WHERE子句,“id”表示RC和LV表。
对于region_cuboid表,我还会在(world_id,region_id)上有一个索引,以匹配与其连接的区域表。
对于lot_version表,(lot)上的索引或(lot,version,mint_version)上的覆盖索引