2014-01-23 42 views
2

我試圖加快查詢,以找到所有客戶誰購買了1970年以前製造的摩托車,併購買了2010年以後製造的另一個摩托車。由於我的查詢運行速度非常慢,我認爲我需要幫助找到更好的指標。我嘗試都會記錄如下:SQL:如何加快查詢使用索引

CREATE TABLE CUSTOMER (
    id int PRIMARY KEY, 
    fname varchar(30),  
    lname varchar(30) 
); 

CREATE TABLE MOTORCYCLE (
    id int PRIMARY KEY, 
    name varchar(30), 
    year int -- Manufactured year 
); 

CREATE TABLE SALES (
    cid int, 
    mid int, 
    FOREIGN KEY(cid) REFERENCES CUSTOMER(id), 
    FOREIGN KEY(mid) REFERENCES MOTOCYCLE(id), 
    PRIMARY KEY(pid, mid, role) 
); 

指標

這裏是我的索引(我有點與這些猜測,但是這是我的嘗試):

CREATE UNIQUE INDEX customerID on CUSTOMER(id); 
CREATE INDEX customerName on CUSTOMER(fname, lname); 

CREATE UNIQUE INDEX motorcycleID on MOTORCYCLE(id); 
CREATE INDEX motorcycleName on MOTORCYCLE(name); 
CREATE INDEX motorcycleYear on MOTORCYCLE(year); 

CREATE INDEX salesCustomerMotorcycleID on SALES(cid, mid);  
CREATE INDEX salesCustomerID on SALES(cid); 
CREATE INDEX castsMotorcycleID on SALES(mid); 

查詢

我的查詢找到客戶購買1970年以前和2010年以後生產的自行車是在這裏:

SELECT fname, lname 
FROM (SALES INNER JOIN CUSTOMER ON SALES.cid=CUSTOMER.id) INNER JOIN MOTORCYCLE ON MOTORCYCLE.id=SALES.mid 
GROUP BY CUSTOMER.id 
HAVING MIN(MOTORCYCLE.year) < 1970 AND MAX(MOTORCYCLE.year) > 2010; 

這裏有另外一個工作查詢,避免了GROUP BYHAVING條款:

SELECT DISTINCT C.id, fname, lname 
FROM (CUSTOMER as C inner join (SALES as S1 INNER JOIN MOTORCYCLE as M1 ON M1.id=S1.mid) on C.id=S1.cid) inner join (SALES as S2 inner join MOTORCYCLE as M2 on S2.mid=M2.id) on C.id=S2.cid 
WHERE (M1.year < 1970 AND M2.year > 2010); 

任何關於我可以用來加快查詢的各種索引的建議?或者我應該改變我的查詢?

UPDATE

我發現了另一個查詢也可以,但是它也太慢了。它已被添加到上面。儘管如此,找到一個可以加快速度的索引也許會有所幫助。

+1

我想用'JOIN'查詢是我同意更好的方式 – DoNotArrestMe

+0

- 這將是一個整潔的語法,對吧?一個'JOIN'可以加快查詢速度嗎? (我相信這將是一個'INNER JOIN ... ON')我只是將它添加到OP中。 – modulitos

+0

爲什麼你在MOTOCYCLE(年)上使用3個索引? – AlexS

回答

1

當你與EXPLAIN QUERY PLAN檢查你的查詢,可以看到,在這兩種情況下,數據庫查找許多相關記錄它過濾掉不需要的記錄之前(含無用年份)。

以下查詢在匹配前查找摩托車ID;哪一個是更快取決於數據的細節,必須由你來衡量:

SELECT * 
FROM Customer 
WHERE EXISTS (SELECT 1 
       FROM Sales 
       WHERE cid = Customer.id 
       AND mid IN (SELECT id 
          FROM Motorcycle 
          WHERE year < 1970)) 
    AND EXISTS (SELECT 1 
       FROM Sales 
       WHERE cid = Customer.id 
       AND mid IN (SELECT id 
          FROM Motorcycle 
          WHERE year > 2010)); 

SELECT * 
FROM Customer 
WHERE EXISTS (SELECT 1 
       FROM Sales AS s1 
       JOIN Sales AS s2 ON s1.cid = s2.cid 
       WHERE s1.cid = Customer.id 
       AND s1.mid IN (SELECT id 
           FROM Motorcycle 
           WHERE year < 1970) 
       AND s2.mid IN (SELECT id 
           FROM Motorcycle 
           WHERE year > 2010)); 

SQL Fiddle

0

爲什麼在查詢中沒有使用聚合函數時使用group by? 使用不同的替代,如果你不希望看到任何重複

+0

我不確定你的意思 - 我認爲我需要聚合來了解客戶是否在指定的製造年份範圍之外購買了自行車。因此,我使用「GROUP BY」來獲取客戶購買的最大和最小年份的自行車。有關如何更改/改進查詢的任何建議? – modulitos

+0

SELECT fname,lname,DISTINCT(CUSTOMER.id) FROM(SALES INNER JOIN CUSTOMER ON SALES.cid = CUSTOMER.id)INNER JOIN MOTORCYCLE ON MOTORCYCLE.id = SALES.mid WHERE MOTORCYCLE.year <1970 OR MOTORCYCLE.year > 2010; 這應該給你所購買的摩托車在1970年之前或2010年之後 –

+0

沒有製造的所有客戶,這並不工作 - 我需要購買1970年以前生產的摩托車,購買摩托車製造2010年後,我找人所有客戶誰已經買了很舊,很新的自行車。 – modulitos