考虑一种结构,在这种结构中,您与两个表上的条件(where,order by等)有多对一(或一对多)的关系。例如:交叉表索引可能吗?
CREATE TABLE tableTwo (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
eventTime DATETIME NOT NULL,
INDEX (eventTime)
) ENGINE=InnoDB;
CREATE TABLE tableOne (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
tableTwoId INT UNSIGNED NOT NULL,
objectId INT UNSIGNED NOT NULL,
INDEX (objectID),
FOREIGN KEY (tableTwoId) REFERENCES tableTwo (id)
) ENGINE=InnoDB;
和一个示例查询:
select * from tableOne t1
inner join tableTwo t2 on t1.tableTwoId = t2.id
where objectId = '..'
order by eventTime;
比方说,你指数tableOne.objectId
和tableTwo.eventTime
。如果你接着解释上述查询,它将显示“使用filesort”。本质上,它首先应用tableOne.objectId
索引,但它不能应用tableTwo.eventTime
索引,因为该索引是针对整个tableTwo(而不是有限的结果集)的,因此它必须执行手动排序。
因此,是否有办法做一个交叉表索引,所以每次检索结果时都不需要文件夹?喜欢的东西:
create index ind_t1oi_t2et on tableOne t1
inner join tableTwo t2 on t1.tableTwoId = t2.id
(t1.objectId, t2.eventTime);
另外,我看着创建一个视图和索引的是,但不支持对视图索引。
我一直倾向于如果交叉表索引不可行的解决方案是将条件数据复制到一个表中。在这种情况下,这意味着eventTime
将被复制到tableOne
中,并将在tableOne.objectId
和tableOne.eventTime
(基本上手动创建索引)上设置多列索引。不过,我想我会首先找出其他人的经验,看看这是否是最好的方法。
非常感谢!
更新:
这里有载荷试验数据的一些过程和结果进行比较:
drop procedure if exists populate_table_two;
delimiter #
create procedure populate_table_two(IN numRows int)
begin
declare v_counter int unsigned default 0;
while v_counter < numRows do
insert into tableTwo (eventTime)
values (CURRENT_TIMESTAMP - interval 0 + floor(0 + rand()*1000) minute);
set v_counter=v_counter+1;
end while;
end #
delimiter ;
drop procedure if exists populate_table_one;
delimiter #
create procedure populate_table_one
(IN numRows int, IN maxTableTwoId int, IN maxObjectId int)
begin
declare v_counter int unsigned default 0;
while v_counter < numRows do
insert into tableOne (tableTwoId, objectId)
values (floor(1 +(rand() * maxTableTwoId)),
floor(1 +(rand() * maxObjectId)));
set v_counter=v_counter+1;
end while;
end #
delimiter ;
您可以使用这些如下来填充tableOne
在tableTwo
10,000行和20000行(用随机引用tableOne
和随机objectId
s在1和5之间),分别花费26.2和70.77秒来运行我:
call populate_table_two(10000);
call populate_table_one(20000, 10000, 5);
更新2(测试触发SQL):
下面是基于daniHp的触发方法的尝试和测试SQL。当tableOne
被添加或tableTwo
被更新时,这保持dateTime
在tableOne
上同步。此外,如果条件列被复制到连接表中,此方法也适用于多对多关系。在我测试tableOne
中的300,000行和tableTwo
中的200,000行时,具有类似限制的旧查询的速度为0.12秒,新查询的速度仍显示为0.00秒。因此,这有一个明显的改进,而且这种方法应该在数百万行和更远的地方表现良好。
alter table tableOne add column tableTwo_eventTime datetime;
create index ind_t1_oid_t2et on tableOne (objectId, tableTwo_eventTime);
drop TRIGGER if exists t1_copy_t2_eventTime;
delimiter #
CREATE TRIGGER t1_copy_t2_eventTime
BEFORE INSERT ON tableOne
for each row
begin
set NEW.tableTwo_eventTime = (select eventTime
from tableTwo t2
where t2.id = NEW.tableTwoId);
end #
delimiter ;
drop TRIGGER if exists upd_t1_copy_t2_eventTime;
delimiter #
CREATE TRIGGER upd_t1_copy_t2_eventTime
BEFORE UPDATE ON tableTwo
for each row
begin
update tableOne
set tableTwo_eventTime = NEW.eventTime
where tableTwoId = NEW.id;
end #
delimiter ;
和更新的查询:
select * from tableOne t1
inner join tableTwo t2 on t1.tableTwoId = t2.id
where t1.objectId = 1
order by t1.tableTwo_eventTime desc limit 0,10;
您可以创建另一个聚合表。 – anttir 2011-12-14 19:34:23
@anttir:是否有理由优于复制现有表之一中的数据? – Briguy37 2011-12-14 20:03:33