| ||||||||||||
![]() |
![]() |
| | LinkBack | Thread Tools | Search this Thread | Display Modes |
(#1)
|
(#2)
|
(#3)
|
(#4)
|
| Operations Manager Posts: 5,419 Join Date: Jan 2006 Location: United Kingdom |
17-06-2008, 01:59 PM
Hi Nick, Your change to the query assumes we are using indices. If we were, your query would indeed speed things up. However, indices are not used on this table. We'll investigate the slow searching problem and if it can be duplicated, see what we can do about it. -------------------------------------------------------------------
|
| | |
(#5)
|
(#6)
|
| New Member Posts: 13 Join Date: Sep 2006 |
18-06-2008, 04:26 AM
I think you should also implement the following change: Code: diff modules/tickets/functions_search.php.orig modules/tickets/functions_search.php
123c123
< $dbCore->query("REPLACE INTO `". TABLE_PREFIX ."ticketpostindex` (`ticketwordid`, `ticketpostid`, `insubject`) VALUES ".implode(",",$postindexsql).";");
---
> $dbCore->query("INSERT IGNORE INTO `". TABLE_PREFIX ."ticketpostindex` (`ticketwordid`, `ticketpostid`, `insubject`) VALUES ".implode(",",$postindexsql).";");
There are only 3 columns in this table; ticketwordid, ticketpostid, and insubject. All 3 of these columns are also in a UNIQUE KEY constraint. A REPLACE INTO will delete every row from the table that matches the query, then reinsert them. All values needed for an INSERT are being supplied by the application, thereforth doing the DELETE first has no purpose and wastes disk IO. |
| | |
(#7)
|
| New Member Posts: 13 Join Date: Sep 2006 |
18-06-2008, 04:31 AM
I'm also running into speed issues when you search for a Creator/Replier on the quick search. Currently the query does a %% search, which requires each row to be read off the disk. Again, slow if you have large amounts of data. Code: # Time: 080617 15:44:53 # User@Host: kayako[kayako] @ localhost [] # Query_time: 21 Lock_time: 0 Rows_sent: 23 Rows_examined: 446207 SELECT `ticketid` FROM `swtickets` WHERE email LIKE '%user@example.com%' ORDER BY `lastactivity` DESC LIMIT 50; # Time: 080617 15:45:13 # User@Host: kayako[kayako] @ localhost [] # Query_time: 20 Lock_time: 0 Rows_sent: 30 Rows_examined: 255180 SELECT `ticketid` FROM `swticketposts` WHERE email LIKE '%user@example.com%' LIMIT 50; Which takes just as long. I have the following index on swtickets that could be used if there wasn't a leading %: KEY `tickets4` (`email`,`subject`), As for swticketposts, I have the following index which could be used if there wasn't a leading %: KEY `ticketposts2` (`email`,`subjecthash`), EDIT: Eh, I striped out the leading % but then I run into the issue where the system tries to do a look up on fullname: SELECT `ticketid` FROM `swtickets` WHERE fullname LIKE '%user@example.com%' LIMIT 50 |
| | |
(#8)
|
| Developer Posts: 619 Join Date: Dec 2007 Location: Idaho | A number of these criticisms show a lack of understanding of the MySQL optimization engine. Quote:
Quote:
Quote:
Quote:
I recommend you attempt this modification on a test database that you've filled with lots of data, then profile the difference. Besides, data from all varbinary descended types (the blobs, the texts and the binaries) is not stored in the table, unless you explicitly request a prefix, which you'll note we have not, by looking at line 142 of setup.php. To quote MySQL :: MySQL 5.0 Reference Manual :: 10.4.3 The BLOB and TEXT Types : "Each BLOB or TEXT value is represented internally by a separately allocated object. This is in contrast to all other data types, for which storage is allocated once per column when the table is opened." Quote:
Code: mysql> explain SELECT `departmentid`, `ticketstatusid`, COUNT(*) AS totalitems, MAX(`lastactivity`) AS lastactivity FROM `swtickets` GROUP BY `departmentid`, `ticketstatusid` HAVING `departmentid` IN ('3');
+----+-------------+-----------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | swtickets | index | NULL | tickets3 | 12 | NULL | 5 | Using index |
+----+-------------+-----------+-------+---------------+----------+---------+------+------+-------------+
Quote:
That actually slows down a standard helpdesk, and introduces a ticket loss bug under some configurations. Quote:
PHP Code: Quote:
No. However, if you've been altering your database, it looks like you've done some fairly significant damage. Quote:
Quote:
Code: mysql> create table foo(id integer key, other integer); Query OK, 0 rows affected (0.03 sec) mysql> insert into foo values(1,1); Query OK, 1 row affected (0.00 sec) mysql> insert ignore into foo values(1,2); Query OK, 0 rows affected (0.00 sec) mysql> select * from foo; +----+-------+ | id | other | +----+-------+ | 1 | 1 | +----+-------+ 1 row in set (0.00 sec) mysql> replace into foo values(1,2); Query OK, 2 rows affected (0.00 sec) mysql> select * from foo; +----+-------+ | id | other | +----+-------+ | 1 | 2 | +----+-------+ 1 row in set (0.00 sec) Quote:
Insert ignore is significantly slower than replace into. Replace into can just add the data to known-usable space and update the index. Insert ignore has to go check whether that data exists first, then remove it from the transaction set. Not only is the replacement query incorrect, it's another massive speed loss. You really should start profiling these things. Quote:
Quote:
The official desk has several terabytes of data in it, and we get a sender search in about a second and a half on a normal commodity blade with a standard raid 1+0 disk setup. It is not unlikely that the damage done to your desk has also corrupted your master BTREE index; consider doing some mysql repair work. MySQL :: MySQL 5.0 Reference Manual :: 6.4.3 How to Repair Tables MySQL :: MySQL 5.0 Reference Manual :: 12.5.2.6 REPAIR TABLE Syntax -------------------------------------------------------------------
| |||||||||||||
| | |
(#9)
|
| New Member Posts: 13 Join Date: Sep 2006 |
19-06-2008, 07:57 PM
Quote:
Wow, actually I am a recognized MySQL Expert by MySQL AB. As you will see when I point your the issues below. I have been working directly with MySQL for 10 years an MySQL AB employees for at least 6 years. Quote:
Quote:
Quote:
Quote:
If you use the InnoDB table handler, there are two different methods: per-table tablespace and raw devices. MySQL :: MySQL 5.0 Reference Manual :: 13.2.3 InnoDB Configuration. Both store the format in a .frm. The first stores all content in ibdata files, the second stores the index and data for each table in an .ibd file per table. Separating large TEXT based columns into their own table is a practice used by many around the world. I have used it for years on applications I have that contain millions upon millions of rows. LiveJournal, one of the largest open source applications out there, and a frequent speaker/presenter at MySQL User Conferences specifically does this for their blogs. I doubt any ticket system ever used by Kayako will get close to the level of data stored by LiveJournal. Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Um, there isn't a single query currently in the ticketing module that uses FULLTEXT indexing. Both tickets and ticketposts do not use FULLTEXT() as an index type, nor is there a query that uses MATCH ... AGAINST() which is the only way to do a full text search in the modules/tickets/ directory. Quote:
Quote:
Quote:
| ||||||||||||||
| | |
(#10)
|
| New Member Posts: 13 Join Date: Sep 2006 |
19-06-2008, 08:19 PM
I thought of something additional to prove why moving a HAVING clause to the WHERE clause is more efficient. Please analyze the two following EXPLAIN syntaxes carefully: Code: mysql> explain SELECT `departmentid`, `ticketstatusid`, COUNT(*) AS totalitems, MAX(`lastactivity`) AS lastactivity FROM `swtickets` GROUP BY `departmentid`, `ticketstatusid` HAVING `departmentid` IN ('3');
+----+-------------+-----------+-------+---------------+-------------+---------+------+--------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+-------------+---------+------+--------+-------+
| 1 | SIMPLE | swtickets | index | NULL | ticketcount | 12 | NULL | 454787 | |
+----+-------------+-----------+-------+---------------+-------------+---------+------+--------+-------+
1 row in set (0.00 sec)
mysql> SELECT `departmentid`, `ticketstatusid`, COUNT(*) AS totalitems, MAX(`lastactivity`) AS lastactivity FROM `swtickets` GROUP BY `departmentid`, `ticketstatusid` HAVING `departmentid` IN ('3');
+--------------+----------------+------------+--------------+
| departmentid | ticketstatusid | totalitems | lastactivity |
+--------------+----------------+------------+--------------+
| 3 | 0 | 159 | 1200986822 |
| 3 | 1 | 4 | 1213928185 |
| 3 | 2 | 123 | 1213928079 |
| 3 | 3 | 30123 | 1213927070 |
| 3 | 4 | 9931 | 1213904199 |
| 3 | 5 | 2422 | 1213908731 |
| 3 | 6 | 1 | 1213922581 |
+--------------+----------------+------------+--------------+
7 rows in set (17.13 sec)
Code: mysql> explain SELECT `departmentid`, `ticketstatusid`, COUNT(*) AS totalitems, MAX(`lastactivity`) AS lastactivity FROM `swtickets` WHERE DepartmentID IN ('3') GROUP BY `departmentid`, `ticketstatusid` ;
+----+-------------+-----------+------+-------------------------------------------------+----------+---------+-------+--------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+-------------------------------------------------+----------+---------+-------+--------+-----------------------------------------------------------+
| 1 | SIMPLE | swtickets | ref | ticketcount,tickets3,tickets5,tickets6,tickets8 | tickets3 | 4 | const | 119210 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+-----------+------+-------------------------------------------------+----------+---------+-------+--------+-----------------------------------------------------------+
mysql> SELECT `departmentid`, `ticketstatusid`, COUNT(*) AS totalitems, MAX(`lastactivity`) AS lastactivity FROM `swtickets` WHERE DepartmentID IN ('3') GROUP BY `departmentid`, `ticketstatusid` ;
+--------------+----------------+------------+--------------+
| departmentid | ticketstatusid | totalitems | lastactivity |
+--------------+----------------+------------+--------------+
| 3 | 0 | 159 | 1200986822 |
| 3 | 1 | 4 | 1213928185 |
| 3 | 2 | 123 | 1213928079 |
| 3 | 3 | 30123 | 1213927070 |
| 3 | 4 | 9931 | 1213904199 |
| 3 | 5 | 2422 | 1213908731 |
| 3 | 6 | 1 | 1213922581 |
+--------------+----------------+------------+--------------+
7 rows in set (0.08 sec)
|
| | |
(#11)
|
(#12)
|
| Member Posts: 148 Join Date: Feb 2008 |
16-07-2008, 04:15 AM
Hi nick, I'm not sure but I assume, due to the size of the database, that you are currently storing all attachments on the database, am I correct? I recommend you to store all attachments with the filesystem method, and migrate all current database attachments using Craigbrass free attachment migration tool Attachment Migration Tool [FREE - EXTERNAL LINK]. This tool will help you release a little bit of size from the database, it's not the core solution but it will help you gain a little bit more of performance. Email & MSN: andres[at]dewak.com Skype: andres.dewak Dewak: Kayako Development, Consultancy and Support http://www.dewak.com |
| | |
![]() |
| Tags |
| scalability |
| Thread Tools | Search this Thread |
| Display Modes | |
| |