Searching large dataset, best way to speed this up i'm querying a table full of vehicles, however each one of these vehicles MUST have another row within another table. This query is currently taking way too long!
Do I need to index the table, or is there another way I can do the query to improve this?
SELECT *
FROM vehicles v
WHERE v.group = 0
AND EXISTS (
    SELECT count(id) FROM quotes quote
    WHERE quote.vehicle_id = v.id
    AND quote.term = 60 
    AND quote.annual_mileage = 8000
    AND quote.deposit = 250
    AND quote.credit_rating = &quot;Excellent&quot;
) IS NOT NULL

vehicles table:
CREATE TABLE `vehicles` (
    `id` INT(11) NOT NULL DEFAULT '0',
    `group_id` INT(11) NOT NULL DEFAULT '0',
    `title` VARCHAR(8) NOT NULL DEFAULT '' COLLATE 'latin1_swedish_ci'
    PRIMARY KEY (`id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;

quotes table:
CREATE TABLE `quotes` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `vehicle_id` INT(11) NOT NULL,
    `credit_rating` VARCHAR(20) NOT NULL COLLATE 'latin1_swedish_ci',
    `deposit` DECIMAL(7,2) NOT NULL,
    `term` TINYINT(2) NOT NULL,
    `annual_mileage` INT(11) NOT NULL
    PRIMARY KEY (`id`) USING BTREE,
    INDEX `vehicle_id` (`vehicle_id`) USING BTREE,
    INDEX `covering_ndx1` (`term`, `annual_mileage`, `deposit`, `credit_rating`, `vehicle_id`) USING BTREE,
    CONSTRAINT `FK_quotes_vehicles` FOREIGN KEY (`vehicle_id`) REFERENCES `database`.`vehicles` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;

Edit:
Updated the create SQL above to reflex the changes I have made. This reduces my query from 0.516 to 0.032
Yes, an index on quote.vehicle_id would help this greatly.
As a general rule† it is a good idea to have an index on columns that are foreign keys, and you should define it as a foreign key with:
FOREIGN KEY (vehicle_id) REFERENCES vehicles(id)

This way the database will help verify your data and prevent a family of potential bugs happening.
Also you will find mySQL's query planner/engine produces a more efficient plan if you use WHERE EXISTS. Your sub-select with GROUP BY will force it to run that part once per outer row when more efficient strategies could be available. Also EXISTS can exit early, once the first matching row is found, but a subquery with an aggregate as above will stop that happening so more rows may be read and considered which is not needed:
SELECT *
FROM vehicles v
WHERE v.group = 0
AND EXISTS (
    SELECT id FROM quotes quote
    WHERE quote.vehicle_id = v.id
    AND quote.term = 60 
    AND quote.annual_mileage = 8000
    AND quote.deposit = 250
    AND quote.credit_rating = &quot;Excellent&quot;
    ) 

You still want the index on quote.vehicle_id for this to avoid full table scanning.
† There are valid exceptions to this rule, which is part of why most database engines don't create such an index automatically, but they are fairly rare.