title: How to speed up MYSQL query with multiple joins?
body: <p>looking for help to speed up this query:</p>
  <pre><code>SELECT tickets.ticketid, datenew, products.name 
  FROM tickets 
  INNER JOIN ticketlines ON tickets.id = ticketlines.ticket 
  INNER JOIN products ON ticketlines.product = products.id 
  INNER JOIN receipts ON receipts.id = tickets.id 
  WHERE (category !='feb765ef-c8a8-4fa2-969c-90f67fe6b3be' AND category!='888f4893-f300-43b5-9933-d549ade744e0' AND category !='8f2031e8-64a4-4abf-8175-3d2bedd9f950' AND category !='ca370ced-1c3b-434c-905e-ec1bc709543b' AND category !='f92ff0ac-fa11-4a5f-a3dd-e0d9ed9c171a' AND category !='445e8605-1cd9-4714-b3fd-7389ac29c206' and category !='05143c54-8a7e-4ce2-97cc-f84f9cf41395' AND category !='8c78afea-b9e2-44cf-b497-c384045b3202' AND category !='95919f7f-ff2e-4aa1-8110-ef63c022c01b' AND category !='f4f88b05-38a1-4956-9182-4c04a0808df7') AND datedone IS NULL 
  ORDER BY ticketid
  </code></pre>
  <p>This is from a cash register database that I am using to pull data for order display.  The structure is the receipt has the primary id, the timein and timedone(DATEDONE) timestamps.  The ticket table has ticket id which is the same as receipt id.  Ticketlines table is the line items on the receipt/ticket.  And then Products table has the human readable definitions of the products.</p>
  <p>The query is to pull all items that aren't completed, i.e. DATEDONE is null, and display the items that were ordered.</p>
  <p>Ticket and Receipt tables have 15K rows, Ticketlines has ~20K rows, Products has 1.5k.</p>
  <p>Pretty small data.  But this query takes over 20 seconds.  I think since I am using primary key IDs for everything, I don't need to index anything, but I am a total noob, so I'm happy to be told I'm wrong.  I'll appreciate any help and can provide any further details.  Thanks!</p>
  <p>EDIT:</p>
  <p>per comments, I am showing table structures.  I'm sorry for the formatting nightmare, I'm unfamiliar with this platform and unsure how to make it more readable :-(</p>
  <pre><code>| receipts | CREATE TABLE `receipts` (
    `ID` varchar(255) NOT NULL,
    `MONEY` varchar(255) NOT NULL,
    `DATENEW` datetime NOT NULL,
    `ATTRIBUTES` mediumblob,
    `PERSON` varchar(255) DEFAULT NULL,
    `DATEDONE` datetime DEFAULT NULL,
    PRIMARY KEY (`ID`),
    KEY `RECEIPTS_FK_MONEY` (`MONEY`),
    KEY `RECEIPTS_INX_1` (`DATENEW`),
    CONSTRAINT `RECEIPTS_FK_MONEY` FOREIGN KEY (`MONEY`) REFERENCES `closedcash` (`MONEY`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
  
  
  | tickets | CREATE TABLE `tickets` (
    `ID` varchar(255) NOT NULL,
    `TICKETTYPE` int(11) NOT NULL DEFAULT '0',
    `TICKETID` int(11) NOT NULL,
    `PERSON` varchar(255) NOT NULL,
    `CUSTOMER` varchar(255) DEFAULT NULL,
    `STATUS` int(11) NOT NULL DEFAULT '0',
    `DONE` varchar(255) DEFAULT NULL,
    PRIMARY KEY (`ID`),
    KEY `TICKETS_FK_2` (`PERSON`),
    KEY `TICKETS_CUSTOMERS_FK` (`CUSTOMER`),
    KEY `TICKETS_TICKETID` (`TICKETTYPE`,`TICKETID`),
    CONSTRAINT `TICKETS_CUSTOMERS_FK` FOREIGN KEY (`CUSTOMER`) REFERENCES `customers` (`ID`),
    CONSTRAINT `TICKETS_FK_2` FOREIGN KEY (`PERSON`) REFERENCES `people` (`ID`),
    CONSTRAINT `TICKETS_FK_ID` FOREIGN KEY (`ID`) REFERENCES `receipts` (`ID`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
  
  
  | ticketlines | CREATE TABLE `ticketlines` (
    `TICKET` varchar(255) NOT NULL,
    `LINE` int(11) NOT NULL,
    `PRODUCT` varchar(255) DEFAULT NULL,
    `ATTRIBUTESETINSTANCE_ID` varchar(255) DEFAULT NULL,
    `UNITS` double NOT NULL,
    `PRICE` double NOT NULL,
    `TAXID` varchar(255) NOT NULL,
    `ATTRIBUTES` mediumblob,
    PRIMARY KEY (`TICKET`,`LINE`),
    KEY `TICKETLINES_FK_2` (`PRODUCT`),
    KEY `TICKETLINES_ATTSETINST` (`ATTRIBUTESETINSTANCE_ID`),
    KEY `TICKETLINES_FK_3` (`TAXID`),
    CONSTRAINT `TICKETLINES_ATTSETINST` FOREIGN KEY (`ATTRIBUTESETINSTANCE_ID`) REFERENCES `attributesetinstance` (`ID`),
    CONSTRAINT `TICKETLINES_FK_2` FOREIGN KEY (`PRODUCT`) REFERENCES `products` (`ID`),
    CONSTRAINT `TICKETLINES_FK_3` FOREIGN KEY (`TAXID`) REFERENCES `taxes` (`ID`),
    CONSTRAINT `TICKETLINES_FK_TICKET` FOREIGN KEY (`TICKET`) REFERENCES `tickets` (`ID`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
  
  | products | CREATE TABLE `products` (
    `ID` varchar(255) NOT NULL,
    `REFERENCE` varchar(255) NOT NULL,
    `CODE` varchar(255) NOT NULL,
    `CODETYPE` varchar(255) DEFAULT NULL,
    `NAME` varchar(255) NOT NULL,
    `PRICEBUY` double NOT NULL,
    `PRICESELL` double NOT NULL,
    `CATEGORY` varchar(255) NOT NULL,
    `TAXCAT` varchar(255) NOT NULL,
    `ATTRIBUTESET_ID` varchar(255) DEFAULT NULL,
    `STOCKCOST` double DEFAULT NULL,
    `STOCKVOLUME` double DEFAULT NULL,
    `IMAGE` mediumblob,
    `ISCOM` bit(1) NOT NULL DEFAULT b'0',
    `ISSCALE` bit(1) NOT NULL DEFAULT b'0',
    `ISKITCHEN` bit(1) NOT NULL DEFAULT b'0',
    `PRINTKB` bit(1) NOT NULL DEFAULT b'0',
    `SENDSTATUS` bit(1) NOT NULL DEFAULT b'0',
    `ISSERVICE` bit(1) NOT NULL DEFAULT b'0',
    `ATTRIBUTES` mediumblob,
    `DISPLAY` varchar(255) DEFAULT NULL,
    PRIMARY KEY (`ID`),
    UNIQUE KEY `PRODUCTS_INX_0` (`REFERENCE`),
    UNIQUE KEY `PRODUCTS_INX_1` (`CODE`),
    UNIQUE KEY `PRODUCTS_NAME_INX` (`NAME`),
    KEY `PRODUCTS_FK_1` (`CATEGORY`),
    KEY `PRODUCTS_TAXCAT_FK` (`TAXCAT`),
    KEY `PRODUCTS_ATTRSET_FK` (`ATTRIBUTESET_ID`),
    CONSTRAINT `PRODUCTS_ATTRSET_FK` FOREIGN KEY (`ATTRIBUTESET_ID`) REFERENCES `attributeset` (`ID`),
    CONSTRAINT `PRODUCTS_FK_1` FOREIGN KEY (`CATEGORY`) REFERENCES `categories` (`ID`),
    CONSTRAINT `PRODUCTS_TAXCAT_FK` FOREIGN KEY (`TAXCAT`) REFERENCES `taxcategories` (`ID`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
  </code></pre>
  <p>Also, here is EXPLAIN output:</p>
  <pre><code>| id | select_type | table       | partitions | type   | possible_keys            | key     | key_len | ref                                | rows  | filtered | Extra                                        |
  +----+-------------+-------------+------------+--------+--------------------------+---------+---------+------------------------------------+-------+----------+----------------------------------------------+
  |  1 | SIMPLE      | receipts    | NULL       | ALL    | PRIMARY                  | NULL    | NULL    | NULL                               | 14624 |    10.00 | Using where; Using temporary; Using filesort |
  |  1 | SIMPLE      | tickets     | NULL       | eq_ref | PRIMARY                  | PRIMARY | 767     | receipts.ID         |     1 |   100.00 | NULL                                         |
  |  1 | SIMPLE      | ticketlines | NULL       | ref    | PRIMARY,TICKETLINES_FK_2 | PRIMARY | 767     | receipts.ID         |     1 |   100.00 | Using where                                  |
  |  1 | SIMPLE      | products    | NULL       | eq_ref | PRIMARY,PRODUCTS_FK_1    | PRIMARY | 767     | ticketlines.PRODUCT |     1 |    97.97 | Using where                                  |
  +----+-------------+-------------+------------+--------+--------------------------+---------+---------+------------------------------------+-------+----------+----------------------------------------------+
  4 rows in set, 1 warning (0.04 sec)
  </code></pre>