它现在使用Contact
的复合索引,但EXPLAIN
仅列出Address
的fkey索引,既不列出我的多列索引也不列出任何其他单列索引。
EXPLAIN EXTENDED SELECT c.*
FROM Contact_Contact c
LEFT OUTER JOIN Address a ON c.id=a.Contact_id
WHERE c.deleted<>1
AND c.external<>1
AND (
c.firstName LIKE 'abc%' OR
c.lastName LIKE 'abc%' OR
c.Company LIKE 'abc%' OR
c.label LIKE 'abc%' OR
a.street LIKE 'abc%' OR
a.city LIKE 'abc%' OR
a.region LIKE 'abc%')
GROUP BY c.id
ORDER BY c.lastName ASC
LIMIT 30
输出:
# id, select_type, table, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, SIMPLE, c, range, myCompositeContactIdx,firstNameIdx,lastNameIdx, myCompositeContactIdx, 1, , 66241, 100.00, Using where; Using temporary; Using filesort
1, SIMPLE, a, ref, FK_dc6mn93h87cim4yr8nnijj3fa,myCompositeAddressIdx , FK_dc6mn93h87cim4yr8nnijj3fa, 17, c.id, 1, 100.00, Using where
(FK_dc6mn93h87cim4yr8nnijj3fa
是Address.Contact_id
)
所以看起来它使用Contact
上的多列索引,但它不使用Address
上的多列,其定义为:
ADD INDEX `myCompositeAddressIdx` USING BTREE (
`Contact_id` ASC, `street`(255) ASC, `city`(255) ASC, `region`(255) ASC
);
知道如何使用myCompositeAddressIdx
?
这是我的新查询,需要250毫秒(旧:350毫秒)
SELECT c.*
FROM Contact_Contact c
WHERE c.deleted<>1
AND c.external<>1
AND (
c.firstName LIKE 'abc%' OR
c.lastName LIKE 'abc%' OR
c.Company LIKE 'abc%' OR
c.label LIKE 'abc%' OR
c.id IN (SELECT a.Contact_id FROM Address a WHERE a.street LIKE 'abc%' OR a.city LIKE 'abc%' OR a.region LIKE 'abc%')
-- ALTERNATIVE:
-- EXISTS (SELECT 1 FROM Address a WHERE a.Contact_id=c.id AND (a.street LIKE 'abc%' OR a.city LIKE 'abc%' OR a.region LIKE 'abc%'))
)
GROUP BY c.id
ORDER BY c.lastName ASC
LIMIT 30
(IN
和EXISTS
似乎同样快“
但EXPLAIN
仍然说,它不使用Address
表上的索引:
# id, select_type, table, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, PRIMARY, c, range, myCompositeContactIdx,firstNameIdx,lastNameIdx, myCompositeContactIdx, 1, , 67138, 100.00, Using where; Using filesort
2, DEPENDENT SUBQUERY, a, index_subquery, FK_dc6mn93h87cim4yr8nnijj3fa,myCompositeAddressIdx,myNEWCompositeAddressIdx, FK_dc6mn93h87cim4yr8nnijj3fa, 17, func, 1, 100.00, Using where
将myNEWCompositeAddressIdx
定义为:
ADD INDEX `myNEWCompositeAddressIdx` USING BTREE (
`street`(255) ASC, `city`(255) ASC, `region`(255) ASC
);
我们的MySQL数据库存在一些性能问题,架构如下:
TABLE Contact:
id, firstName, lastName, company
TABLE Address:
id, contact_id, street, city
TABLE ContactGroup:
id, name
TABLE Contact_ContactGroup:
contact_id, contact_group_id
(还有一些表,但它总是一样的) (所有文本字段都是VARCHAR(最多255个))
我们的查询与输入"abc xyz"
SELECT c.*
FROM Contact c
LEFT JOIN Address a ON a.contact_id = c.id
LEFT JOIN Contact_ContactGroup ccg ON ccg.contact_id = c.id
WHERE
(
c.firstName LIKE 'abc%' OR c.firstName LIKE 'xyz%' OR
c.lastName LIKE 'abc%' OR c.lastName LIKE 'xyz%' OR
c.company LIKE 'abc%' OR c.company LIKE 'xyz%' OR
a.street LIKE 'abc%' OR a.street LIKE 'xyz%' OR
a.city LIKE 'abc%' OR a.city LIKE 'xyz%'
) AND
ccg.contact_group_id IN (1, 2, 3)
GROUP BY
c.id
ORDER BY
c.lastName ASC
在我的开发机器上,接触表中大约130,000行需要 280ms 。 (我们的服务器需要超过2秒)
我们之前有一个DISTINCT
而不是GROUP BY
,但它似乎几乎相同。之前我们还有LIKE '%abc%'
,但我读到如果在搜索词前面有一张外卡,MySQL就无法使用索引。该查询大约需要 310毫秒。
正如您所看到的,查询速度并没有明显提高。我想我确实把索引设置错了。我设置的内容:
Contact Index: primary key
id
Contact Index: BTREE
firstName ASC, lastName ASC, company ASC
Address Index: primary key
id
Address Index: BTREE
street ASC, city ASC
Contact_ContactGroup: compound primary key
contact_id, contact_group_id
我在中添加了索引所有数据已经在表格中。 MySQL会自动索引旧数据吗?添加索引的时间不会超过半秒,但我不确定它是否确实对数据进行了索引。而且我找不到强制重新索引表格的命令。
或者对每列使用单列索引而不是对所有列使用巨大的复合索引更好吗?
顺便说一下:我们正在使用MySQL 5.5和InnoDB Tables。
任何帮助将不胜感激。谢谢:)
答案 0 :(得分:-1)
是否依赖于系统,导致此查询在我的服务器上耗时180毫秒, 我碰巧拥有你的数据库模式的精确副本,我也在PL / SQL过程开发之前编写了索引。
SELECT c.*
FROM Contact c LEFT JOIN Contact_ContactGroup ccg ON ccg.contact_id = c.id
LEFT JOIN Address a ON a.contact_id = c.id
WHERE
c.firstName LIKE 'abc%xyz%' OR
c.lastName LIKE 'abc%xyz%' OR
c.company LIKE 'abc%xyz%' OR
a.street LIKE 'abc%xyz%' OR
a.city LIKE 'abc%xyz%' AND
ccg.contact_group_id IN (1, 2, 3)
GROUP BY
c.id
ORDER BY
c.lastName ASC