(使用Oracle)
我有一个像这样的键/值对的表:
create table MESSAGE_INDEX
(
KEY VARCHAR2(256) not null,
VALUE VARCHAR2(4000) not null,
MESSAGE_ID NUMBER not null
)
我现在想要查找key ='someKey'并且值为'val1','val2'或'val3'的所有消息 - OR值为null,在这种情况下,表中根本没有条目。这是为了节省空间;如果我将它们全部存储,会有大量具有空值的键。
我认为这有效:
SELECT message_id
FROM message_index idx
WHERE ((key = 'someKey' AND value IN ('val1', 'val2', 'val3'))
OR NOT EXISTS (SELECT 1 FROM message_index WHERE key = 'someKey'
AND idx.message_id = message_id))
但是非常慢。在message_index中使用700K记录需要8秒,并且在我的测试环境之外移动时会有更多记录和更多搜索条件。
主键是key,value,message_id:
add constraint PK_KEY_VALUE primary key (KEY, VALUE, MESSAGE_ID)
我为message_id添加了另一个索引,以加快搜索丢失的密钥:
create index IDX_MESSAGE_ID on MESSAGE_INDEX (MESSAGE_ID)
我将在每次搜索中执行其中几项键/值查找,而不仅仅是如上所示的一次。到目前为止,我正在嵌套它们,其中一个级别的输出id是下一个级别的输入。 E.g:
SELECT message_id from message_index
WHERE (key/value compare)
AND message_id IN
(
SELECT ... and so on
)
我该怎么做才能加快速度?
答案 0 :(得分:1)
“我该怎么做才能加快速度?”
使用标准化数据模型而不是键值存储。 重建消息的(特别是可选的)属性将是一个持续的性能问题。
答案 1 :(得分:0)
如果您有一个密钥,保证所有邮件都有:
SELECT message_id
FROM message_index mi
WHERE mi.key = 'GuaranteedKey'
AND mi.message_id IN
(
SELECT message_id
FROM message_index mk
WHERE mk.key = 'someKey'
AND mk.value IN (1, 2, 3)
)
UNION ALL
SELECT message_id
FROM message_index mi
WHERE mi.key = 'GuaranteedKey'
AND mi.message_id NOT IN
(
SELECT message_id
FROM message_index mk
WHERE mk.key = 'someKey'
)
如果你不这样做:
WITH mi AS
(
SELECT DISTINCT message_id
FROM message_index
)
SELECT message_id
FROM mi
WHERE mi.message_id IN
(
SELECT message_id
FROM message_index mk
WHERE mk.key = 'someKey'
AND mk.value IN (1, 2, 3)
)
UNION ALL
SELECT message_id
FROM mi
WHERE mi.message_id NOT IN
(
SELECT message_id
FROM message_index mk
WHERE mk.key = 'someKey'
)
答案 2 :(得分:0)
为了加快速度,你可以将子选择转换为连接,这样你的查询就会变成这样:
SELECT idx.message_id
FROM message_index idx
LEFT JOIN message_index idx2 ON idx2.message_id = idx.message_id AND idx2.key = 'someKey'
WHERE (idx.key = 'someKey' AND idx.value IN ('val1', 'val2', 'val3'))
OR idx2.message_id IS NULL
答案 3 :(得分:0)
我不确定你的第二个滤镜是你想要的。基本上是子查询:
(SELECT 1
FROM message_index
WHERE key = 'someKey'
AND idx.message_id = message_id)
仅当表中的'someKey'
没有键message_id
时,才会包含行。
如果这真的是你想要的,并且因为所有列都是非NULL,你可以用NOT IN重写查询(可能会优化为HASH ANTI-JOIN):
SELECT message_id
FROM message_index idx
WHERE (key = 'someKey' AND VALUE IN ('val1', 'val2', 'val3'))
UNION ALL
SELECT message_id
FROM message_index
WHERE message_id NOT IN (SELECT message_id
FROM message_index
WHERE key = 'someKey');