我试图在一个包含约200k记录的表上使用以下查询。有各种其他字段可以过滤,但这是一个基本的例子。
SELECT b.isbn FROM books b
WHERE
b.price IS NOT NULL AND
b.deleted = '' AND
b.publication_date <= '2009-12-04' AND
(
b.subject1_id IN ('CAT1','CAT2','CAT3','CAT4','CAT5') OR
b.subject2_id IN ('CAT1','CAT2','CAT3','CAT4','CAT5') OR
b.subject3_id IN ('CAT1','CAT2','CAT3','CAT4','CAT5')
)
目前,我在所有这些字段上都有一个单独的索引,这个查询需要大约4.5秒,这太长了。 EXPLAIN
列出了密钥下的NULL
。
我还尝试创建一个包含上述查询中所有字段的大型索引,但EXPLAIN
显示未使用此多字段索引。
如何索引这些字段以加快查询速度?
编辑:这是我当前的索引(查询似乎没有使用它们):
EDIT2:Perʞɔıu的答案 - 在对表进行规范化并基本上使用他的查询之后,它确实加速了一些(现在时间约为3.5秒),但没有我想要的那么多。我将新表索引为PRIMARY KEY(isbn,subject_id),并且该索引用于连接。
EDIT3:我在第二个表(subject_id,isbn)上添加了一个额外的索引,这有帮助。下面提到的其他索引的添加有助于一点点,但只有在我对查询使用“FORCE INDEX”时才会使用。现在已降至约1.5秒。是否有希望降低它?
答案 0 :(得分:3)
在这种情况下,索引在任何帮助之前都需要规范化架构。
您可以创建另一个包含(subject,isbn)的表,在book和subject上添加索引,然后加入该表,如:
select b.isbn from books b
inner join book_subject bs on bs.isbn=b.isbn
where
b.price is not null and b.deleted != 'DELETED'
AND b.publication_date <= '2009-12-04'
AND bs.subject in ('CAT1', 'CAT2'...)
架构规范化中的规则#1(字面意思)是:“no repeating groups”。 在3个主题列的where子句中进行OR操作将阻止您能够利用该部分查询的索引。
(更新以反映isbn是主键)
答案 1 :(得分:0)
我会更多地考虑您的查询实际意味着什么,这可能有助于引导您的答案。
让我们去除它以向你展示这个问题。
SELECT b.isbn FROM books b
WHERE
b.price IS NOT NULL AND
b.deleted != 'DELETED' AND
b.publication_date <= '2009-12-04' AND
(
b.subject1_id = 'CAT1' OR
b.subject1_id = 'CAT2' OR
b.subject1_id = 'CAT3' OR
b.subject1_id = 'CAT4' OR
b.subject1_id = 'CAT5' OR
b.subject2_id = 'CAT1' OR
b.subject2_id = 'CAT2' OR
b.subject2_id = 'CAT3' OR
b.subject2_id = 'CAT4' OR
b.subject2_id = 'CAT5' OR
b.subject3_id = 'CAT1' OR
b.subject3_id = 'CAT2' OR
b.subject3_id = 'CAT3' OR
b.subject3_id = 'CAT4' OR
b.subject3_id = 'CAT5'
)
除了(price,deleted,publication_date,subject1)之外,显然没有任何索引可用于其他主题。
索引中有哪些字段?
答案 2 :(得分:0)
关于尼克的帖子:
创建另一个包含的表 (subject,book_id),添加索引 书和主题:
拥有
会不会更清晰select b.isbn from books b
where
#various table b where restrictions
AND b.isbn IN (
Select isbn
from book_subject bs
where bs.subject IN ('CAT1', 'CAT2' ...)
)
答案 3 :(得分:0)
首先:MySQL在选择期间每个表只能使用一个索引。它试图选择最好的索引,但有时服务器无法决定几个原因。如果你有很多语句一次只运行一个where子句,那么每个只有一个字段的索引只会有所帮助。
要在此优化:您需要创建一个包含字段
的索引price
deleted
publication_date
请勿包含类别,因为您使用的是OR子句。
ALTER TABLE `test`.`books` ADD INDEX `idxPriceDeletedPublication`(`price`, `deleted`, `publication_date`);
然后应该为您提供以下EXPLAIN输出:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: b
type: range
possible_keys: idxPriceDeletedPublication
key: idxPriceDeletedPublication
key_len: 5
ref: NULL
rows: 1
Extra: Using where
1 row in set (0.00 sec)