您可以添加一个复合(concept, attrib, value, business_key)
索引,以便查询(如果 MySQL 决定使用此索引)可以找到索引中的所有信息,而无需读取整个表。
您的查询相当于:
SELECT DISTINCT business_key
FROM Memory
WHERE NOT (concept = 'case' AND attrib = 'status' AND value = 'closed')
对此(可能会产生相同的执行计划):
SELECT business_key
FROM Memory
WHERE NOT (concept = 'case' AND attrib = 'status' AND value = 'closed')
GROUP BY business_key
由于要放入索引的 4 列都是VARCHAR(255)
,因此索引长度会很大。MyISAM 不允许超过 1000 字节,InnoDB 不允许超过 3072。
一种解决方案是削减最后一部分的长度,使索引长度小于 1000: 255+255+255+230 = 995
:
(concept, attrib, value, business_key(220))
它会起作用,但是从性能方面来说,索引长度如此之大确实不好。
如果这符合您希望存储在那里的数据,另一种选择是降低这 4 列的全部或部分的长度。255
如果您希望100
在一列中有最大值,则无需声明长度。
您可以考虑的另一个选择是将这 4 列放在 4 个单独的参考表中。(或者只是有重复数据的列。似乎business_key
会有重复的数据,但没有那么多。因此,为该列制作参考表并不是很好。)
示例:将concept
值放入新表中,如下所示:
CREATE TABLE Concept_Ref
( concept_id INT AUTO_INCREMENT
, concept VARCHAR(255)
, PRIMARY KEY concept_id
, UNIQUE INDEX concept_idx (concept)
) ;
INSERT INTO Concept_Ref
( concept )
SELECT DISTINCT
concept
FROM
Memory ;
然后Memory
使用以下命令更改表:
ALTER TABLE Memory
ADD COLUMN concept_id INT ;
这样做(一次):
UPDATE
Memory m
JOIN
Concept_Ref c
ON c.concept = m.concept
SET m.concept_id = c.concept_id
然后删除Memory.concept
列:
ALTER TABLE Memory
DROP COLUMN concept ;
FOREIGN KEY
如果您将表从 MyISAM 更改为 InnoDB,您还可以添加引用。
在对所有 4 列执行相同操作后,不仅表中新复合索引的长度Memory
会小得多,而且您的表大小也会小得多。此外,使用任何这些列的任何其他索引都将具有较小的长度。
当然,查询需要编写 4 个 JOIN。并且该表的任何INSERT
, UPDATE
orDELETE
语句都必须进行更改和精心设计。
但总的来说,我认为你会有更好的表现。使用您现在的设计,似乎'case'
,'status'
和'closed'
的值重复了很多次。