MySql 本例为单列索引或多列索引
MySql single column index or multi-column index in this case
我有以下简化的 table 'places'
,其中包含 200,000 多行:
placeId INT(10)
placeName VARCHAR (30)
placeNameEnglish VARCHAR (30)
placeName
是以原始语言存储的地名,例如罗纳
placeNameEnglish
是翻译成英文的地名,例如罗纳
目前我有两个单列索引 - 一个用于 placeName
,一个用于 placeNameEnglish
,并且正在执行这些 LIKE
模式查询:
$testStr = 'rho';
SELECT placeId
FROM places
WHERE (placeName LIKE '$testStr%' OR placeNameEnglish LIKE '$testStr%')
进行了一些研究,但在这种情况下使用时无法完全理解多列索引。问题是,我应该将 placeName
和 placeNameEnglish
组合成一个多列索引还是将它们保留为单独的索引?
更新
正在努力实施@Gordon Linoff 建议的最后一个建议。
考虑添加一个名为 translations
的 table 而不是 placeNames
,这样同一个索引可以用于多个 table,即 persons
table 需要相同的 LIKE 'abc%'
匹配。
到目前为止:
transId INT
parentId INT
- placeId
或 personId
parentTypeId TINYINT
- 1
识别 places
table 或 2
识别 persons
table 等(更多 table 以后可以使用此系统)
languageId INT
transName VARCHAR
我是否还应该为 parentTypeId
编制索引以适应识别正确父项 table 所需的额外 WHERE
条件?
例如WHERE transName LIKE 'abc%' AND parentTypeId = 1
我想象 mysql 是这样工作的:它首先使用 transName
的索引来匹配 transName LIKE 'abc%'
,然后使用 parentTypeId = 1
[=43 过滤结果=]
对于此查询:
SELECT placeId
FROM places
WHERE placeName LIKE '$testStr%' OR placeNameEnglish LIKE '$testStr%';
MySQL 可以 使用两个索引,一个在 places(placeName)
上,一个在 places(placeNameEnglish)
上。该操作称为索引合并(请参阅 here)。我不会指望它。该查询不能完全使用复合索引。
您可以将查询改写为:
SELECT placeId
FROM places
WHERE placeName LIKE '$testStr%'
UNION
SELECT placeId
FROM places
WHERE placeNameEnglish LIKE '$testStr%';
或:
SELECT placeId
FROM places
WHERE placeName LIKE '$testStr%'
UNION ALL
SELECT placeId
FROM places
WHERE placeId NOT IN (SELECT placeId FROM places WHERE placename LIKE '$testStr%') AND
placeNameEnglish LIKE '$testStr%';
这些可以利用两个索引。
不过,我的建议是更改数据的结构。有一个名为 PlaceNames
(或类似名称)的 table,其中包含以下列:
placeNameId INT
placeId INT,
languageId INT,
placeName VARCHAR(255)
也就是说,每种语言各占一行。然后,您的查询可以轻松利用 placeName(placeName)
.
上的索引
对于您原来的问题:两个独立的索引。但是……你太辛苦了:
对于欧洲地名,您不需要搜索这两列。 utf8_unicode_ci
(或 utf8_bin
以外的几乎任何排序规则)的大小写折叠和重音不敏感将满足您的需要:
mysql> SELECT 'Rhône' LIKE '%rho%', 'Rhône' LIKE '%xyz%';
+-----------------------+-----------------------+
| 'Rhône' LIKE '%rho%' | 'Rhône' LIKE '%xyz%' |
+-----------------------+-----------------------+
| 1 | 0 |
+-----------------------+-----------------------+
编辑 根据 OP 的评论,这不是一个完整的解决方案。
我有以下简化的 table 'places'
,其中包含 200,000 多行:
placeId INT(10)
placeName VARCHAR (30)
placeNameEnglish VARCHAR (30)
placeName
是以原始语言存储的地名,例如罗纳placeNameEnglish
是翻译成英文的地名,例如罗纳
目前我有两个单列索引 - 一个用于 placeName
,一个用于 placeNameEnglish
,并且正在执行这些 LIKE
模式查询:
$testStr = 'rho';
SELECT placeId
FROM places
WHERE (placeName LIKE '$testStr%' OR placeNameEnglish LIKE '$testStr%')
进行了一些研究,但在这种情况下使用时无法完全理解多列索引。问题是,我应该将 placeName
和 placeNameEnglish
组合成一个多列索引还是将它们保留为单独的索引?
更新
正在努力实施@Gordon Linoff 建议的最后一个建议。
考虑添加一个名为 translations
的 table 而不是 placeNames
,这样同一个索引可以用于多个 table,即 persons
table 需要相同的 LIKE 'abc%'
匹配。
到目前为止:
transId INT
parentId INT
- placeId
或 personId
parentTypeId TINYINT
- 1
识别 places
table 或 2
识别 persons
table 等(更多 table 以后可以使用此系统)
languageId INT
transName VARCHAR
我是否还应该为 parentTypeId
编制索引以适应识别正确父项 table 所需的额外 WHERE
条件?
例如WHERE transName LIKE 'abc%' AND parentTypeId = 1
我想象 mysql 是这样工作的:它首先使用 transName
的索引来匹配 transName LIKE 'abc%'
,然后使用 parentTypeId = 1
[=43 过滤结果=]
对于此查询:
SELECT placeId
FROM places
WHERE placeName LIKE '$testStr%' OR placeNameEnglish LIKE '$testStr%';
MySQL 可以 使用两个索引,一个在 places(placeName)
上,一个在 places(placeNameEnglish)
上。该操作称为索引合并(请参阅 here)。我不会指望它。该查询不能完全使用复合索引。
您可以将查询改写为:
SELECT placeId
FROM places
WHERE placeName LIKE '$testStr%'
UNION
SELECT placeId
FROM places
WHERE placeNameEnglish LIKE '$testStr%';
或:
SELECT placeId
FROM places
WHERE placeName LIKE '$testStr%'
UNION ALL
SELECT placeId
FROM places
WHERE placeId NOT IN (SELECT placeId FROM places WHERE placename LIKE '$testStr%') AND
placeNameEnglish LIKE '$testStr%';
这些可以利用两个索引。
不过,我的建议是更改数据的结构。有一个名为 PlaceNames
(或类似名称)的 table,其中包含以下列:
placeNameId INT
placeId INT,
languageId INT,
placeName VARCHAR(255)
也就是说,每种语言各占一行。然后,您的查询可以轻松利用 placeName(placeName)
.
对于您原来的问题:两个独立的索引。但是……你太辛苦了:
对于欧洲地名,您不需要搜索这两列。 utf8_unicode_ci
(或 utf8_bin
以外的几乎任何排序规则)的大小写折叠和重音不敏感将满足您的需要:
mysql> SELECT 'Rhône' LIKE '%rho%', 'Rhône' LIKE '%xyz%';
+-----------------------+-----------------------+
| 'Rhône' LIKE '%rho%' | 'Rhône' LIKE '%xyz%' |
+-----------------------+-----------------------+
| 1 | 0 |
+-----------------------+-----------------------+
编辑 根据 OP 的评论,这不是一个完整的解决方案。