MySQL索引策略

时间:2009-12-04 20:59:46

标签: mysql query-optimization

我试图在一个包含约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显示未使用此多字段索引。

如何索引这些字段以加快查询速度?

编辑:这是我当前的索引(查询似乎没有使用它们):

  • 指数(价格)
  • 指数(删除)
  • 指数(publication_date)
  • 指数(subject1_id)
  • 指数(subject2_id)
  • 指数(subject3_id)
  • index(price,deleted,publication_date,subject1_id,subject2_id,subject3_id)

EDIT2:Perʞɔıu的答案 - 在对表进行规范化并基本上使用他的查询之后,它确实加速了一些(现在时间约为3.5秒),但没有我想要的那么多。我将新表索引为PRIMARY KEY(isbn,subject_id),并且该索引用于连接。

EDIT3:我在第二个表(subject_id,isbn)上添加了一个额外的索引,这有帮助。下面提到的其他索引的添加有助于一点点,但只有在我对查询使用“FORCE INDEX”时才会使用。现在已降至约1.5秒。是否有希望降低它?

4 个答案:

答案 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)