MySQL with JOINS is very slow - mysql

I have this query:
select
b.user as user1, b.timestamp as ts1,
c.user as user2, c.timestamp as ts2,
d.user as user3, d.timestamp as ts3,
e.user as user4, e.timestamp as ts4,
f.user as user5, f.timestamp as ts5,
g.user as user6, g.timestamp as ts6,
h.user as user7, h.timestamp as ts7,
i.user as user8, i.timestamp as ts8,
j.user as user9, j.timestamp as ts9,
k.user as user10, k.timestamp as ts10,
a.beschreibung, a.auftragsnummer, a.faellig, a.subkunde,
(SELECT firma from kunden where id=a.kunde limit 0,1) as kunde,
(SELECT kommision from kommision where id=a.kommision limit 0,1) as kommision
from auftrag a
left join details b on (b.beschreibung='Step1' AND b.auftrags_id=a.id)
left join details c on (c.beschreibung='Step2' AND c.auftrags_id=a.id)
left join details d on (d.beschreibung='Step3' AND d.auftrags_id=a.id)
left join details e on (e.beschreibung='Step4' AND e.auftrags_id=a.id)
left join details f on (f.beschreibung='Step5' AND f.auftrags_id=a.id)
left join details g on (g.beschreibung='Step6' AND g.auftrags_id=a.id)
left join details h on (h.beschreibung='Step7' AND h.auftrags_id=a.id)
left join details i on (i.beschreibung='Step8' AND i.auftrags_id=a.id)
left join details j on (j.beschreibung='Step9' AND j.auftrags_id=a.id)
left join details k on (k.beschreibung='Step10' AND k.auftrags_id=a.id)
where a.erledigt='1'
It runs very, very slow and take about 1 Minute to get a resultset.
Table "auftrag" has 820 rows and table "details" about 7000 rows.
What am I doing wrong?
Thanks
Patrick
CREATE TABLE auftrag
(
id INT(10) NOT NULL AUTO_INCREMENT,
beschreibung VARCHAR(255) NULL DEFAULT '0',
auftragsnummer VARCHAR(50) NULL DEFAULT '0',
faellig VARCHAR(50) NULL DEFAULT NULL,
kunde INT(11) NULL DEFAULT NULL,
subkunde VARCHAR(50) NULL DEFAULT NULL,
kommision VARCHAR(50) NULL DEFAULT NULL,
notiz TEXT NULL,
werbeanbringung TEXT NULL,
erledigt INT(1) NULL DEFAULT NULL,
INDEX Schlüssel 1 (id),
INDEX Schlüssel 2 (id, auftragsnummer, kunde, subkunde, beschreibung)
) COLLATE='latin1_swedish_ci' ENGINE=MyISAM AUTO_INCREMENT=850 ;
CREATE TABLE details
(
id INT(11) NOT NULL AUTO_INCREMENT,
auftrags_id VARCHAR(50) NULL DEFAULT '0',
beschreibung VARCHAR(50) NULL DEFAULT '0',
user VARCHAR(50) NULL DEFAULT '0',
timestamp VARCHAR(50) NULL DEFAULT '0',
notiz VARCHAR(255) NULL DEFAULT NULL,
INDEX Schlüssel 2 (user, timestamp, beschreibung, auftrags_id),
INDEX Schlüssel 1 (id, user, timestamp, beschreibung)
) COLLATE='latin1_swedish_ci' ENGINE=MyISAM AUTO_INCREMENT=7260 ;

You have no indexes on your tables that are useful for this query, and you are joining one table against another repeatedly.
On the auftrag table add an index on the erledigt column.
On the details table add an index covering both the beschreibungand the auftrags_id columns
It may also be possible to avoid most of the joins if you are prepared to process the returned data afterwards (ie, split up a returned field into an array). But a bit messy:-
SELECT
GROUP_CONCAT(CONCAT_WS('##', b.beschreibung, b.user, b.timestamp)),
a.beschreibung, a.auftragsnummer, a.faellig, a.subkunde,
(SELECT firma from kunden where id=a.kunde limit 0,1) as kunde,
(SELECT kommision from kommision where id=a.kommision limit 0,1) as kommision
FROM auftrag a
LEFT OUTER JOIN details b on b.auftrags_id=a.id AND b.beschreibung IN ('Step1', 'Step2', 'Step3', 'Step4', 'Step5', 'Step6', 'Step7', 'Step8', 'Step9', 'Step10')
WHERE a.erledigt='1'
GROUP BY a.id
EDIT - I have just noticed that the id on the auftrag table is an INT field (as I would expect) but the auftrags_id column on the details table is a VARCHAR(50) field. This will dramatically affect performance as it needs to convert the values for every single comparison.
Note that Gordons comment above on the order of the fields on the index does apply (how much will depend on the actual data - for example how many other values of beschreibung there are), but without fixing this problem with the mismatched data types changing the index will almost certainly not help.

For your query, you want the following indexes:
auftrag(erledigt, id)
details(auftrags_id, beschreibung)
kunden(kunde, firma)
You can also rewrite the query as a conditional aggregation, but the right indexes will be a big help.
Note: the order of the columns in the composite indexes is important.

This is probably a case where InnoDB will be a clear winner over MyISAM. In details, have PRIMARY KEY(auftrags_id, beschreibung).
Meanwhile, in auftrag, PRIMARY KEY(id). And the indexes Gordon suggests for auftrag and kunden.

Related

select taking 9.+ seconds. how to re-write it better?

I have this select:
select t.id, c.user, t.title, pp.foto, t.data from topics t
inner join cadastro c on t.user = c.id
left join profile_picture pp on t.user = pp.user
left join (
select c.topic, MAX(c.data) cdata from comments c
group by c.topic
)c on t.id = c.topic
where t.community = ?
order by ifnull(cdata, t.data) desc
limit 15
I want to select topics and order them by their date or the date of the topic comments, if it has comments.
Unfortunately, this is taking more than 9 seconds.
I don't think the problem here is indexing, but the way I am writing the select itself.
`topics` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user` INT(11) UNSIGNED NOT NULL,
`title` varchar(100) NOT NULL,
`description` varchar(1000),
`community` INT(11) UNSIGNED NOT NULL,
`data` datetime NOT NULL,
`ip` varchar(20),
PRIMARY KEY (`id`),
FOREIGN KEY (`user`) REFERENCES cadastro (`id`),
FOREIGN KEY (`community`) REFERENCES discussion (`id`)
)
`comments` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user` INT(11) UNSIGNED NOT NULL,
`comment` varchar(1000) NOT NULL,
`topic` INT(11) UNSIGNED NOT NULL,
`data` datetime NOT NULL,
`ip` varchar(20),
`delete` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
FOREIGN KEY (`user`) REFERENCES cadastro (`id`),
FOREIGN KEY (`topic`) REFERENCES topics (`id`)
)
Your EXPLAIN gives you a strong hint. The first row in that results says, using temporary, using filesort implying that it's not using a an index.
It might be possible to improve this query by adding indexes and removing some conditionals, but I think in this case a better solution exists.
Why not add a new column to topics that indicates the last time a comment was added? (like a last_modified). Every time a comment gets added, just update that column for that topic as well.
It's effectively denormalizing this. I think this a valid usecase and it's always going to be faster than fixing this messy query.
You are performing a full table scan on the table comments on every query. How many rows does it have? At least create the following index:
comments (topic, data);
to avoid reading the whole table every time.
I know you've said you don't think the problem is indexing, but 9 out of 10 times I've had this problem that's exactly what it's been down to.
Ensure you have an index created on each table that you're using in the query and include the columns specified in the join.
Also, as NiVeR said, don't use the same alias multiple times.
Here's a refactoring of that query, unsure if I've mixed up or missed a column name/alias or two though.
select t.id, c.user, t.title, pp.foto, t.data from topics t
inner join cadastro c on t.user = c.id
left join profile_picture pp on t.user = pp.user
left join (
select com.topic, MAX(com.data) comdata from comments com
group by com.topic
)com1 on t.id = com1.topic
where t.community = ?
order by ifnull(com1.comdata, t.data) desc
limit 15

Improve speed of MySQL query with 5 left joins

Working on a support ticketing system with not a lot of tickets (~3,000). To get a summary grid of ticket information, there are five LEFT JOIN statements on custom field table (j25_field_value) containing about 10,000 records. The query runs too long (~10 seconds) and in cases with a WHERE clause, it runs even longer (up to ~30 seconds or more).
Any suggestions for improving the query to reduce the time to run?
Four tables:
j25_support_tickets
CREATE TABLE `j25_support_tickets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category_id` int(11) NOT NULL DEFAULT '0',
`user_id` int(11) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`subject` varchar(255) DEFAULT NULL,
`message` text,
`modified_date` datetime DEFAULT NULL,
`priority_id` tinyint(3) unsigned DEFAULT NULL,
`status_id` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3868 DEFAULT CHARSET=utf8
j25_support_priorities
CREATE TABLE `j25_support_priorities` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8
j25_support_statuses
CREATE TABLE `j25_support_statuses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
j25_field_value (id, ticket_id, field_id, field_value)
CREATE TABLE `j25_support_field_value` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ticket_id` int(11) DEFAULT NULL,
`field_id` int(11) DEFAULT NULL,
`field_value` tinytext,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=10889 DEFAULT CHARSET=utf8
Also, ran this:
SELECT LENGTH(field_value) len FROM j25_support_field_value ORDER BY len DESC LIMIT 1
note: the result = 38
The query:
SELECT DISTINCT t.id as ID
, (select p.title from j25_support_priorities p where p.id = t.priority_id) as Priority
, (select s.title from j25_support_statuses s where s.id = t.status_id) as Status
, t.subject as Subject
, t.email as SubmittedByEmail
, type.field_value AS IssueType
, ver.field_value AS Version
, utype.field_value AS UserType
, cust.field_value AS Company
, refno.field_value AS RefNo
, t.modified_date as Modified
FROM j25_support_tickets AS t
LEFT JOIN j25_support_field_value AS type ON t.id = type.ticket_id AND type.field_id =1
LEFT JOIN j25_support_field_value AS ver ON t.id = ver.ticket_id AND ver.field_id =2
LEFT JOIN j25_support_field_value AS utype ON t.id = utype.ticket_id AND utype.field_id =3
LEFT JOIN j25_support_field_value AS cust ON t.id = cust.ticket_id AND cust.field_id =4
LEFT JOIN j25_support_field_value AS refno ON t.id = refno.ticket_id AND refno.field_id =5
ALTER TABLE j25_support_field_value
ADD INDEX (`ticket_id`,`field_id`,`field_value`(50))
This index will work as a covering index for your query. It will allow the joins to use only this index to look up the values. It should perform massively faster than without this index, since currently your query would have to read every row in the table to find what matches each combination of ticket_id and field_id.
I would also suggest converting your tables to InnoDB engine, unless you have a very explicit reason for using MyISAM.
ALTER TABLE tablename ENGINE=InnoDB
As above - a better index would help. You could probably then simplify your query into something like this too (join to the table only once):
SELECT t.id as ID
, p.title as Priority
, s.title as Status
, t.subject as Subject
, t.email as SubmittedByEmail
, case when v.field_id=1 then v.field_value else null end as IssueType
, case when v.field_id=2 then v.field_value else null end as Version
, case when v.field_id=3 then v.field_value else null end as UserType
, case when v.field_id=4 then v.field_value else null end as Company
, case when v.field_id=5 then v.field_value else null end as RefNo
, t.modified_date as Modified
FROM j25_support_tickets AS t
LEFT JOIN j25_support_field_value v ON t.id = v.ticket_id
LEFT JOIN j25_support_priorities p ON p.id = t.priority_id
LEFT JOIN j25_support_statuses s ON s.id = t.status_id;
You can do away with the subqueries for starters and just get them from another join. You can add an index to j25_support_field_value
alter table j25_support_field_value add key(id, field_type);
I assume there is an index on id in j25_support_tickets - if not and if they are unique, add a unique index alter table j25_support_tickets add unique key(id); If they're not unique, remove the word unique from that statement.
In MySQL, a join usually requires an index on the field(s) that you are using to join on. This will hold up and produce very reasonable results with huge tables (100m+), if you follow that rule, you will not go wrong.
are the ids in j25_support_tickets unique? If they are you can do away with the distinct - if not, or if you are getting exact dupicates in each row, still do away with the distinct and add a group by t.id to the end of this:
SELECT t.id as ID
, p.title as Priority
, s.title as Status
, t.subject as Subject
, t.email as SubmittedByEmail
, type.field_value AS IssueType
, ver.field_value AS Version
, utype.field_value AS UserType
, cust.field_value AS Company
, refno.field_value AS RefNo
, t.modified_date as Modified
FROM j25_support_tickets AS t
LEFT JOIN j25_support_field_value AS type ON t.id = type.ticket_id AND type.field_id =1
LEFT JOIN j25_support_field_value AS ver ON t.id = ver.ticket_id AND ver.field_id =2
LEFT JOIN j25_support_field_value AS utype ON t.id = utype.ticket_id AND utype.field_id =3
LEFT JOIN j25_support_field_value AS cust ON t.id = cust.ticket_id AND cust.field_id =4
LEFT JOIN j25_support_field_value AS refno ON t.id = refno.ticket_id AND refno.field_id =5
LEFT JOIN j25_support_priorities p ON p.id = t.priority_id
LEFT JOIN j25_support_statuses s ON s.id = t.status_id;
Switch to InnoDB.
After switching to InnoDB, make the PRIMARY KEY for j25_support_field_value be (ticket_id, field_id) (and get rid if id). (Tacking on field_value(50) will hurt, not help.)
A PRIMARY KEY is a UNIQUE KEY, so don't have both.
Use VARCHAR(255) instead of the nearly-equivalent TINYTEXT.
EAV schema sucks. My ran on EAV.

Left join does not meet my requirement

There are two tables over here: first is for basic details of "poll" and
second for the "answer". My requirement is like this:
i want poll records to display only for users who didn't answer the poll
I tried this query but it is not working:
select p.* from mycom_poll as p
LEFT JOIN mycom_polls_result as pr on (p.b_id != pr.b_poll_id
And pr.b_user_id !=14) where p.v_status = 'enable'
And p.v_country like '%India%'
AND p.d_activate_date <= '2015-04-17' order by p.b_id limit 1"
CREATE TABLE IF NOT EXISTS `mycom_poll` (
`b_id` bigint(20) NOT NULL AUTO_INCREMENT,
`b_user_id` bigint(20) NOT NULL DEFAULT '0',
`v_code` varchar(50) NOT NULL,
`v_question` varchar(1000) CHARACTER SET utf8 NOT NULL,
`v_country` varchar(100) NOT NULL,
`d_activate_date` date NOT NULL,
`dt_created_date` datetime NOT NULL,
`dt_updated_date` datetime NOT NULL,
`v_ip` varchar(20) NOT NULL,
`v_status` varchar(20) NOT NULL DEFAULT 'enable',
PRIMARY KEY (`b_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
INSERT INTO `mycom_poll` (`b_id`, `b_user_id`, `v_code`, `v_question`, `v_country`, `d_activate_date`, `dt_created_date`, `dt_updated_date`, `v_ip`, `v_status`) VALUES(8, 0, '20150417115406-192168113C5ZJpXu2hM', 'Who is chief minstor of Gujarat in 2015 Rajyasabha?', '["Global","India","United States"]', '2015-04-15', '2015-04-17 11:56:12', '2015-04-18 07:29:11', '127.0.0.1', 'enable');
CREATE TABLE IF NOT EXISTS `mycom_polls_result` (
`b_id` bigint(20) NOT NULL AUTO_INCREMENT,
`b_poll_id` bigint(20) NOT NULL,
`b_user_id` bigint(20) NOT NULL,
`b_poll_answer` bigint(20) NOT NULL,
`dt_created_date` datetime NOT NULL,
`dt_updated_date` datetime NOT NULL,
`v_ip` varchar(20) NOT NULL,
`v_status` varchar(20) NOT NULL DEFAULT 'enable',
PRIMARY KEY (`b_id`),
KEY `b_poll_id` (`b_poll_id`,`b_user_id`),
KEY `b_poll_id_2` (`b_poll_id`,`b_user_id`,`b_poll_answer`),
KEY `b_poll_id_3` (`b_poll_id`,`b_user_id`,`b_poll_answer`),
KEY `b_user_id` (`b_user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `mycom_polls_result` (`b_id`, `b_poll_id`, `b_user_id`, `b_poll_answer`, `dt_created_date`, `dt_updated_date`, `v_ip`, `v_status`) VALUES
(1, 8, 14, 64, '2015-04-18 13:27:50', '2015-04-18 13:27:50', '127.0.0.1', 'enable');
Your query:
select p.* from mycom_poll as p
LEFT JOIN mycom_polls_result as pr on (p.b_id != pr.b_poll_id
And pr.b_user_id !=14) where p.v_status = 'enable'
And p.v_country like '%India%'
AND p.d_activate_date <= '2015-04-17' order by p.b_id limit 1
First I am going to point out the mistake of this query, what you are doing here is, you are left joining two tables on id of first table not equals to id of second table which will join all the table data whose ids are not same, when you do a left join, you always get the data of left table and if data not present in right table you get null.
So in where clause you should check any if the field of second table is null or not like this.
select p.* from mycom_poll as p
LEFT JOIN mycom_polls_result as pr on p.b_id = pr.b_poll_id
where pr.b_user_id !=14 p.v_status = 'enable'
And p.v_country like '%India%' AND p.d_activate_date <= '2015-04-17'
and pr.b_poll_id is null order by p.b_id limit 1
I request you to understand left join first.
At the moment you are using LEFT JOIN which is correct to force all rows of the mycom_poll table to be considered, but you're joining on p.b_id != pr.b_poll_id which will associate each poll row in mycom_poll with all the unrelated results rows in mycom_polls_result that don't belong to it.
You probably need to join on p.b_id = pr.b_poll_id, and then require rows with pr.b_poll_id IS NULL in your WHERE clause.
You also seem to be trying to restrict results to pr.b_user_id !=14, which is fine, but that needs to be stated along with other filtering conditions in the WHERE clause. The LEFT JOIN ON clause is just going to be used to declare the column relationships between your tables.
SELECT p.*
FROM mycom_poll as p
LEFT JOIN mycom_polls_result as pr
ON p.b_id = pr.b_poll_id
WHERE
pr.b_user_id !=14
AND p.v_status = 'enable'
AND p.v_country like '%India%'
AND p.d_activate_date <= '2015-04-17'
AND pr.b_poll_id IS NULL
ORDER BY p.b_id LIMIT 1
HTH

Lots of temporary tables in MySQL

I am running website which i have below two queries which are very much repetitive. And in MySQL innoDB processes in can see they are taking lots of time and whenever i see processes those are there they keep on creating temporary tables and takes long to execute taking lots of memory and CPU.
They were really bad i somehow manage to optimised these.. but i am not able to do beyond that.
$getmoddetails = "SELECT a.id, a.name, a.defvar, a.description, a.icon, a.thumb, a.average_rating, a.total_rating, c.rating, a.group_access, d.long_name, a.editor_id, e.users_count
FROM dir_cat_item AS b
INNER JOIN dir_item AS a ON a.id = b.item_id
AND a.status = 'O'
LEFT JOIN dir_item_notation_user_map AS c ON a.id = c.item_id
AND c.user_id =%u
LEFT JOIN users AS d ON d.id = a.editor_id
LEFT JOIN (SELECT item_id, COUNT(*) AS users_count
FROM module
GROUP BY item_id) AS e ON e.item_id = b.item_id
WHERE a.id=%u";
$getnbModules_by_col = "SELECT
posx,COUNT(posx) as nb
FROM module WHERE
user_id = %u
AND profile_id = %u
GROUP BY posx
ORDER BY posx ASC";
Table index on Module
- item_id
- user_id
- profile_id
- uniq
For USERS Table
- id
- username
Any suggestion please...
Update :-
CREATE TABLE IF NOT EXISTS `module` (
`item_id` mediumint(8) unsigned NOT NULL DEFAULT '0',
`user_id` int(10) unsigned NOT NULL DEFAULT '0',
`profile_id` int(3) unsigned NOT NULL DEFAULT '0',
`posx` tinyint(3) unsigned NOT NULL DEFAULT '0',
`posy` tinyint(3) unsigned NOT NULL DEFAULT '0',
`posj` tinyint(3) unsigned NOT NULL DEFAULT '0',
`x` smallint(5) unsigned NOT NULL DEFAULT '0',
`y` smallint(5) unsigned NOT NULL DEFAULT '0',
`typ` char(1) CHARACTER SET utf8 NOT NULL DEFAULT 'D',
`variables` text COLLATE utf8_unicode_ci,
`uniq` smallint(5) unsigned NOT NULL DEFAULT '1',
`blocked` tinyint(1) unsigned NOT NULL DEFAULT '0',
`minimized` tinyint(1) unsigned NOT NULL DEFAULT '0',
`old_id` tinyint(3) unsigned DEFAULT NULL,
`feed_id` mediumint(8) unsigned NOT NULL DEFAULT '0',
`shared` varchar(33) COLLATE utf8_unicode_ci DEFAULT NULL,
`currentview` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
KEY `item_id` (`item_id`,`user_id`,`profile_id`,`uniq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
item_id 18 A No
user_id 393467 A No
profile_id 393467 A No
uniq 393467 A No
Thank you in advance
For best performance of that second query, you'd need an appropriate index on the module table, e.g.
... ON module (user_id, profile_id, posx)
For the first query, you'd likely benefit from a different index on the module table:
... ON module (item_id)
But without the table definitions, datatype and cardinality of the columns, it's really impossible to make definitive suggestions.
In your first query, I'd suggest you add a predicate in the inline view (derived table) aliased as e. I don't think MySQL is pushing the predicate from the outer query into the inline view.
( SELECT item_id
, COUNT(*) AS users_count
FROM module
WHERE item_id = %u
GROUP BY item_id
) AS e
You're going to need to supply the same value in that WHERE clause as you are providing in the WHERE clause on the outer query. From what I'm reading there...
e.item_id = b.item_id = a.id = %u
By adding that WHERE clause in that inline view, that should cut down the number or rows retrieved from the module table, and that derived table will have just one row. An index with a leading column of item_id would be a covering index. The EXPLAIN PLAN should show Using index and not show Using filesort.
If your first query is pulling back a relatively small number of rows, you might consider a correlated subquery on the module table, in place of a join to the derived table (aliased as e) in your first query (to avoid materializing a large derived table). (In general, however, correlated subqueries can be real performance killers. But in some cases, where the outer query is pulling back a small number of rows, the repeated execution of the subquery can actually perform better than generating a large derived table, which you only need a few rows from.)
SELECT a.id
, a.name
, a.defvar
, a.description
, a.icon
, a.thumb
, a.average_rating
, a.total_rating
, c.rating
, a.group_access
, d.long_name
, a.editor_id
, ( SELECT SUM(1)
FROM module e
WHERE e.item_id = b.item_id
AND e.item_id = %u
) AS users_count
FROM dir_cat_item b
JOIN dir_item a
ON a.id = b.item_id
AND b.item_id = %u
AND a.status = 'O'
LEFT
JOIN dir_item_notation_user_map c
ON c.item_id = a.id
AND c.item_id = %u
AND c.user_id = %u
LEFT
JOIN users d
ON d.id = a.editor_id
WHERE a.id = %u

How to join two tables without messing up the query

I have this query for example (good, it works how I want it to)
SELECT `discusComments`.`memberID`, COUNT( `discusComments`.`memberID`) AS postcount
FROM `discusComments`
GROUP BY `discusComments`.`memberID` ORDER BY postcount DESC
Example Results:
memberid postcount
3 283
6 230
9 198
Now I want to join the memberid of the discusComments table with that of the discusTopic table (because what I really want to do is only get my results from a specific GROUP, and the group id is only in the topic table and not in the comment one hence the join.
SELECT `discusComments`.`memberID`, COUNT( `discusComments`.`memberID`) AS postcount
FROM `discusComments`
LEFT JOIN `discusTopics` ON `discusComments`.`memberID` = `discusTopics`.`memberID`
GROUP BY `discusComments`.`memberID` ORDER BY postcount DESC
Example Results:
memberid postcount
3 14789
6 8678
9 6987
How can I stop this huge increase happening in the postcount? I need to preserve it as before.
Once I have this sorted I want to have some kind of line which says WHERE discusTopics.groupID = 6, for example
CREATE TABLE IF NOT EXISTS `discusComments` (
`id` bigint(255) NOT NULL auto_increment,
`topicID` bigint(255) NOT NULL,
`comment` text NOT NULL,
`timeStamp` bigint(12) NOT NULL,
`memberID` bigint(255) NOT NULL,
`thumbsUp` int(15) NOT NULL default '0',
`thumbsDown` int(15) NOT NULL default '0',
`status` int(1) NOT NULL default '1',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=7190 ;
.
CREATE TABLE IF NOT EXISTS `discusTopics` (
`id` bigint(255) NOT NULL auto_increment,
`groupID` bigint(255) NOT NULL,
`memberID` bigint(255) NOT NULL,
`name` varchar(255) NOT NULL,
`views` bigint(255) NOT NULL default '0',
`lastUpdated` bigint(10) NOT NULL,
PRIMARY KEY (`id`),
KEY `groupID` (`groupID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=913 ;
SELECT `discusComments`.`memberID`, COUNT( `discusComments`.`memberID`) AS postcount
FROM `discusComments`
JOIN `discusTopics` ON `discusComments`.`topicID` = `discusTopics`.`id`
GROUP BY `discusComments`.`memberID` ORDER BY postcount DESC
Joining the topicid in both tables solved the memberID issue. Thanks #Andiry M
You need to use just JOIN not LEFT JOIN and you can add AND discusTopics.memberID = 6 after ON discusComments.memberID = discusTopics.memberID
You can use subqueries lik this
SELECT `discusComments`.`memberID`, COUNT( `discusComments`.`memberID`) AS postcount
FROM `discusComments` where `discusComments`.`memberID` in
(select distinct memberid from `discusTopics` WHERE GROUPID = 6)
If i understand your question right you do not need to use JOIN here at all. JOINs are needed in case when you have many to many relationships and you need for each value in one table select all corresponding values in another table.
But here you have many to one relationship if i got it right. Then you can simply do select from two tables like this
SELECT a.*, b.id FROM a, b WHERE a.pid = b.id
This is simple request and won't create a giant overhead as JOIN does
PS: In the future try to experiment with your queries, try to avoid JOINs especially in MySQL. They are slow and dangerous in their complexity. For 90% of cases when you want to use JOIN there is simple and much faster solution.