2012-01-10 93 views
1

表模式是這樣的:桌子設計之間的區別?

應用:

applicationid(pk) 
userid(pk) 
applicationname 

服務:

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

我要編寫一個查詢來過濾所有記錄針對特定applciation特定用戶。 userid將有一個'common'值,在這種情況下,所有用戶都將訪問它,並且此常見記錄將具有版本'1'。 如果用戶'a'編輯記錄'common',則編輯的信息將被插入爲帶有用戶標識'a'和版本'2'的新記錄。 在這種情況下,在過濾時,我必須顯示,而不是'普通'記錄,但用戶的記錄版本爲'2'。 對於不對應於任何應用程序的服務,applicationid字段將爲'null',它們將被稱爲外部服務。

對於上述數據模型,我無法編寫將使用索引而不是範圍的過濾器查詢。

編輯: 我必須篩選特定用戶的特定應用程序中的所有記錄。在過濾時,我們必須考慮版本和用戶標識符上的上述要點。所以,過濾約束變得太複雜了。

使用應用程序表是因爲我必須在applicationid不爲空時顯示應用程序名稱[如果服務對應於應用程序]。

說,查詢變得像,

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)大約需要2s。但無論我做什麼,我都無法讓外部查詢佔用任何索引。有什麼建議麼?

請你幫我

  1. 要在一個更好的查詢計劃到達?
  2. 或重新設計表格?
+0

服務表DDL不清楚。請詳細說明我們的要求 – 2012-01-10 09:35:09

+0

我已經添加了一些更多的細節..希望這有助於更好地理解.. :) – Sowmiya 2012-01-10 10:15:49

回答

0

從你寫什麼,我會通過創建以下表中接近數據模型:

  • 用戶(擁有用戶的列表)
  • 應用(持有的應用程序列表)
  • applicationVersion(持有映射到用戶id的應用程序版本列表)
  • 服務(持有服務的列表)
  • serviceApplicatioVersion(HO lds哪個應用程序版本映射到哪個服務)

你甚至可能想引入一個serviceVersion表,然後將一個服務版本映射到應用程序的版本。我無法從你寫的東西中知道服務是否有版本或應用程序。總之,這裏是一些DDL和諾迪例如數據來說明我的意思:

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'; 

你可能不得不調整它取決於你想要什麼很大,但希望它會讓你在正確的去方向。

+0

@湯姆 - 感謝您的輸入:)該版本是爲服務。因此,我可以創建一個表'ServiceVersion [serviceid,userid,version]',它將跟蹤特定用戶的服務版本。如果此表沒有特定用戶的任何條目,我可以將'普通'userid的記錄,以防萬一,存在兩個記錄,一個'Common'和一個userid'a'。我將分析這是如何工作的,並簡化了我的查詢。 – Sowmiya 2012-01-10 10:32:03

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_common中的所有服務檢索與app_ws_user表中特定用戶的編輯版本不同的應用程序相關服務。

如何有效地編寫查詢?