Welcome Guest, Not a member yet? Register   Sign In
how to optimise an sql union containing joins and a subquery ?
#1

[eluser]Unknown[/eluser]
My app uses this sql ...

SELECT * FROM (( SELECT DISTINCT c.companyname,c.tradingas,a.quarantined,c.companyid,a.address1,a.city,a.postcode,a.region,c.origin_dsn,d.title,d.firstname,d.surname,d.position,a.telephoneno,a.companyemail,addresstypes,markets FROM companies c join addresses a on c.companyid = a.companyid join contacts d on c.companyid = d.companyid where d.origin_dsn = 'ifd' and primarycontact = 1 and d.clientid = 0 and c.origin_dsn = 'ifd' and a.origin_dsn = 'ifd' and c.companyid in (select distinct companyid from products where description IN ('Windows and Doors','Vertical Sliders','Bi-Fold Doors') AND type IN ('wd:f','wd:b') AND material = 'PVCu' AND origin_dsn = 'ifd') )UNION( SELECT DISTINCT c.companyname,c.tradingas,a.quarantined,c.companyid,a.address1,a.city,a.postcode,a.region,c.origin_dsn,d.title,d.firstname,d.surname,d.position,a.telephoneno,a.companyemail,addresstypes,markets FROM companies c join addresses a on c.companyid = a.companyid join contacts d on c.companyid = d.companyid where d.origin_dsn = 'ifd' and primarycontact = 1 and d.clientid = 0 and c.origin_dsn = 'ifd' and a.origin_dsn = 'ifd' and c.companyid in (select distinct companyid from products where type IN ('cr:f','cr:b') AND origin_dsn = 'ifd') )) as t where t.quarantined = 0 and t.origin_dsn = 'ifd' and t.region IN ('Northern Counties','North West','Yorkshire','East Midlands','West Midlands','South West','Home Counties','Southern Counties','Greater London','Scotland','Wales','Northern Ireland') order by companyname

it takes a staggering 3.5 seconds to run in mysql query browser (on my slow, low spec laptop)

This query is made of 2 very similar queries that each take about 1.5 seconds.

My app could require up to 4 similar unions.

Can anyone suggest how it might be written more efficiently using the CI api ?
#2

[eluser]TheFuzzy0ne[/eluser]
Holy poop on a stick! That's quite a query!

So long as you have the right indexes set up on your database and your query is optimised (which I don't think it is), I don't think the query should be quite so slow. You can use [url="http://dev.mysql.com/doc/refman/5.0/en/explain.html"]EXPLAIN[/url] to help you figure out where you're missing indexes, or perhaps break the query up into several smaller queries.

I've reformated your query to make it a little easier to read, but IMHO it's still quite cryptic with the alias' you're using.

Code:
SELECT *
FROM (
    (
        SELECT DISTINCT
            c.companyname,
            c.tradingas,
            a.quarantined,
            c.companyid,
            a.address1,
            a.city,
            a.postcode,
            a.region,
            c.origin_dsn,
            d.title,
            d.firstname,
            d.surname,
            d.position,
            a.telephoneno,
            a.companyemail,
            addresstypes,
            markets
        FROM companies c
        JOIN addresses a ON c.companyid = a.companyid
        JOIN contacts d ON c.companyid = d.companyid
        WHERE d.origin_dsn = ‘ifd’
        AND primarycontact = 1
        AND d.clientid = 0
        AND c.origin_dsn = ‘ifd’
        AND a.origin_dsn = ‘ifd’
        AND c.companyid IN (
            SELECT DISTINCT
                companyid
            FROM products
            WHERE description IN (
                ‘Windows and Doors’,
                ‘Vertical Sliders’,
                ‘Bi-Fold Doors’
            )
            AND type IN (
                ‘wd:f’,
                ‘wd:b’
            )
            AND material = ‘PVCu’
            AND origin_dsn = ‘ifd’
        )
    )
    UNION(
        SELECT DISTINCT
            c.companyname,
            c.tradingas,
            a.quarantined,
            c.companyid,
            a.address1,
            a.city,
            a.postcode,
            a.region,
            c.origin_dsn,
            d.title,
            d.firstname,
            d.surname,
            d.position,
            a.telephoneno,
            a.companyemail,
            addresstypes,
            markets
        FROM companies c
        JOIN addresses a ON c.companyid = a.companyid
        JOIN contacts d ON c.companyid = d.companyid
        WHERE d.origin_dsn = ‘ifd’
        AND primarycontact = 1
        AND d.clientid = 0
        AND c.origin_dsn = ‘ifd’
        AND a.origin_dsn = ‘ifd’
        AND c.companyid IN (
            SELECT DISTINCT
                companyid
            FROM products
            WHERE type IN (
                ‘cr:f’,
                ‘cr:b’
            )
            AND origin_dsn = ‘ifd’
        )
    )
) AS t
WHERE t.quarantined = 0
AND t.origin_dsn = ‘ifd’
AND t.region IN (
    ‘Northern Counties’,
    ‘North West’,
    ‘Yorkshire’,
    ‘East Midlands’,
    ‘West Midlands’,
    ‘South West’,
    ‘Home Counties’,
    ‘Southern Counties’,
    ‘Greater London’,
    ‘Scotland’,
    ‘Wales’,
    ‘Northern Ireland’
)
ORDER BY companyname

Hopefully someone else might be able to give you some input.




Theme © iAndrew 2016 - Forum software by © MyBB