表设计的区别?

时间:2012-01-10 09:02:15

标签: mysql performance database-design

表模式如下:

应用:

applicationid(pk)  
userid(pk) 
applicationname

服务:

serviceid(pk) 
userid(pk) 
applicationid
servicename
servicetype 
version 
modifieddate  

我必须编写一个查询来过滤特定用户的特定用户的所有记录。 userid将具有一个值'common',在这种情况下,所有用户都将访问它,并且此公共记录将具有版本'1'。 如果用户'a'编辑记录'common',则编辑的信息将作为具有用户标识'a'和版本'2'的新记录插入。 在这种情况下,在过滤时,我必须显示,而不是“常用”记录,而是显示版本为“2”的用户记录。 对于与任何应用程序不对应的服务,applicationid字段将为“null”,它们将被称为外部服务。

使用上述数据模型,我无法编写将使用索引而不是范围的过滤器查询。

编辑: 我必须过滤特定用户的特定应用程序中的所有记录。我们必须在过滤时考虑版本和用户ID上的上述要点。因此,过滤约束变得过于复杂。

使用Applications表是因为我必须显示applciation名称,以防applicationid不为null [如果服务对应于某个应用程序]。

说,查询变得像,

select ser.*,app.applicationname
from services ser
left join applications app
on ser.userid = app.userid and ser.applicationid = app.applicationid
where (ser.userid = 'user1' OR ser.userid = 'common')
AND (ser.applicationid = 'appid1' OR ser.applicationid IS NULL)
AND (ser.modifieddate < '9999-01-01 00:00:00' OR (ser.modifieddate = '9999-01-01 00:00:00' AND ser.serviceid > ' \n'))
AND ser.version = (select max(ser1.version) 
                     from services ser1
                     where (ser1.userid = 'user1' OR ser1.userid = 'common')
                     AND (ser1.applicationid = 'appid1' OR ser1.applicationid IS NULL)
                     AND ser1.servicename = ser.servicename)
ORDER BY ser.modifieddate,ser.serviceid
LIMIT 0,50

但是这个查询的性能很差。我想优化它。子查询和联接使用索引(applicationid,servicename)(userid,applicationid)时大约需要2秒。但无论我做什么,我都无法使外部查询占用任何索引。有什么建议?

请你帮帮我

  1. 要获得更好的查询计划?
  2. 或重新设计表格?

2 个答案:

答案 0 :(得分:1)

我根据我要存储的数据对服务表进行了分区,如下所示:

CREATE TABLE `app_ws_common` (                                                                                                     
          `serviceid` varchar(16) NOT NULL,                                                                                             
          `applicationid` varchar(16) default NULL,                                                                                     
          `modifieddate` date default NULL,                                                                                             
          `version` decimal(1,0) default NULL,                                                                                          
          `servicename` varchar(20) default NULL,                                                                                       
          `userid` varchar(128) NOT NULL,                                                                                             
          PRIMARY KEY  (`serviceid`,`userid`),                                                                                        
          KEY `table1_isv_fk` (`applicationid`,`userid`),                                                                             
          CONSTRAINT `table1_isv_fk` FOREIGN KEY (`applicationid`, `userid`) REFERENCES `applications` (`applicationid`, `userid`)  
        ) ENGINE=InnoDB DEFAULT CHARSET=latin1



 CREATE TABLE `app_ws_user` (                                                                                                     
           `serviceid` varchar(16) NOT NULL,                                                                                              
           `userid` varchar(128) NOT NULL,                                                                                              
           `applicationid` varchar(16) default NULL,                                                                                      
           `modifieddate` date default NULL,                                                                                              
           `version` decimal(1,0) default NULL,                                                                                           
           `servicename` varchar(20) default NULL,                                                                                        
           PRIMARY KEY  (`serviceid`,`userid`),                                                                                         
           KEY `FK_app_ws_user` (`applicationid`,`userid`),                                                                             

           CONSTRAINT `FK_app_ws_user` FOREIGN KEY (`applicationid`, `userid`) REFERENCES `applications` (`applicationid`, `userid`)  
         ) ENGINE=InnoDB DEFAULT CHARSET=latin1


CREATE TABLE `applications` (                  
            `applicationid` varchar(16) NOT NULL,        
            `userid` varchar(128) NOT NULL,            
            `applicationname` varchar(30) default NULL,  
            PRIMARY KEY  (`applicationid`,`userid`)    
          ) ENGINE=InnoDB DEFAULT CHARSET=latin1  

 CREATE TABLE `external_ws_common` (           
               `serviceid` varchar(16) NOT NULL,        
               `modifieddate` date default NULL,        
               `version` decimal(1,0) default NULL,     
               `servicename` varchar(20) default NULL,  
               PRIMARY KEY  (`serviceid`)               
             ) ENGINE=InnoDB DEFAULT CHARSET=latin1  


CREATE TABLE `external_ws_user` (            
                `serviceid` varchar(16) NOT NULL,          
                `userid` varchar(128) NOT NULL,          
                `applicationid` varchar(16) default NULL,  
                `modifieddate` date default NULL,          
                `version` decimal(1,0) default NULL,       
                `servicename` varchar(20) default NULL,    
                PRIMARY KEY  (`serviceid`,`userid`)      
              ) ENGINE=InnoDB DEFAULT CHARSET=latin1

下面:

app_ws_common 表包含所有用户共有的所有应用相关服务

app_ws_user 表包含特定用户创建的所有与应用程序相关的服务,并从其通用版本进行编辑。

应用程序表将包含应用程序列表和相应的用户。

external_ws_common 表将包含独立于所有应用程序且对所有用户通用的服务列表。

external_ws_user 表将包含与任何应用程序不对应并由用户从“常见”版本的外部服务创建或编辑的服务列表。

现在,我必须从表app_ws_user中检索所有与应用程序相关的服务,并在app_ws_user表中没有该特定用户的编辑版本时从表app_ws_common中检索所有服务。

如何有效地为此编写查询?

答案 1 :(得分:0)

根据您所写的内容,我将通过创建以下表格来接近数据模型:

  • 用户(拥有用户列表)
  • 申请(持有申请表)
  • applicationVersion(包含映射到userId的应用程序版本列表)
  • 服务(持有服务列表)
  • serviceApplicatioVersion(保存哪个应用程序的哪个版本映射到哪个服务)

您甚至可能想要引入serviceVersion表,然后将服务版本映射到应用程序版本。我无法判断您所写的服务是否有版本或应用程序。无论如何,这里有一些DDL和noddy示例数据来说明我的意思:

create table user
(id int unsigned not null primary key auto_increment,
userName varchar(50) not null,
unique key userUIdx (userName));

create table application
(id int unsigned not null primary key auto_increment,
applicationName varchar(50) not null,
unique key applicationUIdx1 (applicationName));

create table applicationVersion
(id int unsigned not null primary key auto_increment,
applicationId int unsigned not null,
version decimal(10,2) unsigned not null default 1.0,
userId int unsigned not null,
modifiedDate timestamp,
unique key applicationVersionUIdx1 (applicationId,version),
constraint `fk_applicationVersion_user1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
constraint `fk_applicationVersion_application1` FOREIGN KEY (`applicationId`) REFERENCES `application` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
);

create table service
(id int unsigned not null primary key auto_increment,
serviceName varchar(50) not null,
serviceType varchar(50) not null,
unique key serviceUIdx1 (serviceName));

create table serviceApplicationVersion
(id int unsigned not null primary key auto_increment,
applicationVersionId int unsigned not null,
serviceId int unsigned not null,
modifiedDate timestamp,
unique key serviceApplicationVersionUIdx1 (applicationVersionId,serviceId),
constraint `fk_serviceApplicationVersion_applicationVersion1` FOREIGN KEY (`applicationVersionId`) REFERENCES `applicationVersion` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
constraint `fk_serviceApplicationVersion_service1` FOREIGN KEY (`serviceId`) REFERENCES `service` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
);

insert into user (userName) values ('common');
insert into user (userName) values ('User A');
insert into user (userName) values ('User B');

insert into application (applicationName) values ('App 1');
insert into application (applicationName) values ('App 2');

insert into applicationVersion (applicationId,version,userId) values (
(select id from application where applicationName = 'App 1'),
1.0,
(select id from user where userName = 'common')
);

insert into applicationVersion (applicationId,version,userId) values (
(select id from application where applicationName = 'App 1'),
2.0,
(select id from user where userName = 'User A')
);

insert into service (serviceName, serviceType) values ('Service 1','Service with apps');
insert into service (serviceName, serviceType) values ('Service 2','Service with no apps');

insert into serviceApplicationVersion (applicationVersionId,serviceId) values (
(select av.id from applicationVersion av inner join application a on a.id = av.applicationId where a.applicationName = 'App 1' and av.version = 2.0),
(select id from service where serviceName = 'Service 1')
);

-- Query to select services,applications and versions in those services and users
select s.serviceName,
a.applicationName,
av.version,
u.userName
from user u
inner join applicationVersion av on av.userId = u.id
inner join serviceApplicationVersion sav on sav.applicationVersionId = av.id
inner join application a on av.applicationId = a.id
inner join service s on s.id = sav.serviceId
where userName = 'User A';

你可能不得不根据你的需要调整它,但希望它会让你朝着正确的方向前进。