Mysql: Selecting id, then * on id is much faster than selecting *. Why? - mysql

I have a MySQL database table (roughly 100K rows):
id BIGINT(indexed), external_barcode VARCHAR(indexed), other simple columns, and a LongText column.
The LongText column is a JSON data dump. I save the large JSON objects because I will need to extract more of the data in the future.
When I run this query it takes 29+ seconds:
SELECT * FROM scraper_data WHERE external_barcode = '032429257284'
EXPLAIN
#id select_type table partitions type possible_keys key key_len ref rows filtered Extra
'1' 'SIMPLE' 'scraper_data' NULL 'ALL' NULL NULL NULL NULL '119902' '0.00' 'Using where'
This more complex query takes 0.00 seconds:
SELECT * FROM scraper_data WHERE id = (
SELECT id FROM scraper_data WHERE external_barcode = '032429257284'
)
EXPLAIN
# id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
'1', 'PRIMARY', 'scraper_data', NULL, 'const', 'PRIMARY,id_UNIQUE', 'PRIMARY', '8', 'const', '1', '100.00', NULL
'2', 'SUBQUERY', 'scraper_data', NULL, 'ALL', NULL, NULL, NULL, NULL, '119902', '0.00', 'Using where'
Less than 6 rows are returned from these queries. Why is the LONGTEXT slowing down the first query given that its not being referenced in the where clause?
CREATE TABLE
CREATE TABLE `scraper_data` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`bzic` varchar(10) NOT NULL,
`pzic` varchar(10) DEFAULT NULL,
`internal_barcode` varchar(20) DEFAULT NULL,
`external_barcode_type` enum('upc','isbn','ean','gtin') DEFAULT NULL,
`external_barcode` varchar(15) DEFAULT NULL,
`url` varchar(255) NOT NULL,
`title` varchar(255) DEFAULT NULL,
`category` varchar(3) DEFAULT NULL,
`description` text,
`logo_image_url` varchar(255) DEFAULT NULL,
`variant_image_urls` text,
`parent_brand` varchar(10) DEFAULT NULL,
`parent_brand_name` varchar(255) DEFAULT NULL,
`manufacturer` varchar(10) DEFAULT NULL,
`manufacturer_name` varchar(255) DEFAULT NULL,
`manufacturer_part_number` varchar(255) DEFAULT NULL,
`manufacturer_model_number` varchar(255) DEFAULT NULL,
`contributors` text,
`content_info` text,
`content_rating` text,
`release_date` timestamp NULL DEFAULT NULL,
`reviews` int(11) DEFAULT NULL,
`ratings` int(11) DEFAULT NULL,
`internal_path` varchar(255) DEFAULT NULL,
`price` int(11) DEFAULT NULL,
`adult_product` tinyint(4) DEFAULT NULL,
`height` varchar(255) DEFAULT NULL,
`length` varchar(255) DEFAULT NULL,
`width` varchar(255) DEFAULT NULL,
`weight` varchar(255) DEFAULT NULL,
`scraped` tinyint(4) NOT NULL DEFAULT '0',
`scraped_timestamp` timestamp NULL DEFAULT NULL,
`scrape_attempt_timestamp` timestamp NULL DEFAULT NULL,
`processed` tinyint(4) NOT NULL DEFAULT '0',
`processed_timestamp` timestamp NULL DEFAULT NULL,
`modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`scrape_dump` longtext,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
UNIQUE KEY `url_UNIQUE` (`url`),
UNIQUE KEY `internal_barcode_UNIQUE` (`internal_barcode`),
KEY `bzic` (`bzic`),
KEY `pzic` (`pzic`),
KEY `internal_barcode` (`internal_barcode`),
KEY `external_barcode` (`external_barcode`,`external_barcode_type`) /*!80000 INVISIBLE */,
KEY `scrape_attempt` (`bzic`,`scraped`,`scrape_attempt_timestamp`)
) ENGINE=InnoDB AUTO_INCREMENT=121674 DEFAULT CHARSET=latin1;

The second query could benefit from the cache that already contains the result of the first query.
In addition in the second subquery you just select use two column (id, external_barcode ) in these two column are in a index all the query result is obtained only with the index scan while in the first query for retrieve all the data the query must scan all the tables row ..
For avoiding the long time for the first query, you should add a proper index on external_barcode column
create index my_idx on scraper_data (external_barcode, id)

Your queries are not equivalent, and your second query will throw an error if you have more than one row with that barcode:
Error Code: 1242. Subquery returns more than 1 row
This is probably what happens here: you do not actually get a result, just an error. Since MySQL can stop the full table scan as soon as it finds a second row, you can get this error faster than a correct result, including "0.00s" if those rows are among the first rows that are scanned (for example in ids 1 and 2).
From the execution plan, you can see that both do a full table scan (which, up to current versions, includes reading the blob field), and thus should perform similarly fast (as the first entry in your 2nd explain plan is neglectable for only a few rows).
So with a barcode that doesn't throw an error, both of your queries, as well as the corrected 2nd query (where you use IN instead of =),
SELECT * FROM scraper_data WHERE id IN ( -- IN instead of = !!
SELECT id FROM scraper_data WHERE external_barcode = '032429257284'
)
as well as running your subquery
SELECT id FROM scraper_data WHERE external_barcode = '032429257284'
separately (which, if your assumption is correct, have to be even faster than your 2nd query) will have a similar (long) execution time.
As scaisEdge mentioned in his answer, an index on external_barcode will improve the performance significantly, as you do not not need to do a full table scan, as well as you do not need to read the blob field. You actually have such an index, but you disabled it (invisible). You can simply reenable it by using
ALTER TABLE scraper_data ALTER INDEX `external_barcode` VISIBLE;

Related

Improving the performance of a MYSQL query with a one-to-many relationship

I have a query in my DB that is taking 25 seconds to return results, which is way too long. It seems like it should be pretty simple. Two tables; the main table (document) is a standard table with some data columns, the join table is a mapping table with only two columns (parent_id, division_id). Previously there wasn't an index on the mapping table so I added one and that changed the "explain" to include the index but doesn't seem to have had an impact on the performance.
The query looks like this:
explain SELECT DISTINCT doc.*
FROM document doc
LEFT JOIN multi_division_mapper divisions ON doc.id = divisions.parent_id
WHERE doc.clientId = 'SOME_GUID'
AND (divisions.division_id IS NULL OR divisions.division_id IN ('SOME_GUID'));
and the results of explain are:
Total number of rows in document: 6720
Total number of rows in mapper: 6173
From what I've been able to gather I need to improve either the "type" or the "extra" to make the query faster. What can I do here?
Create table statements:
CREATE TABLE `document` (
`id` varchar(36) NOT NULL,
`addedBy` varchar(255) DEFAULT NULL,
`addedDate` datetime NOT NULL,
`editedBy` varchar(255) DEFAULT NULL,
`editedDate` datetime NOT NULL,
`deleted` bit(1) DEFAULT NULL,
`clientId` varchar(36) NOT NULL,
`departmentId` varchar(36) DEFAULT NULL,
`documentParentId` varchar(36) DEFAULT NULL,
`documentParent` varchar(50) DEFAULT NULL,
`fileId` varchar(255) DEFAULT NULL,
`fileUrl` varchar(600) DEFAULT NULL,
`documentName` varchar(500) NOT NULL,
`displayName` varchar(255) NOT NULL,
`documentId` varchar(45) DEFAULT NULL,
`notes` varchar(1000) DEFAULT NULL,
`visibility` varchar(45) NOT NULL DEFAULT 'PRIVATE',
`documentType` varchar(45) NOT NULL,
`restrictDelete` bit(1) NOT NULL,
`customData` text,
`releaseDate` datetime NOT NULL,
`expirationDate` datetime NOT NULL,
`isApproved` bit(1) NOT NULL DEFAULT b'0',
`userSupplier` varchar(36) DEFAULT NULL,
`complianceCertificateId` varchar(36) DEFAULT NULL,
`Status` varchar(50) DEFAULT 'NEUTRAL',
PRIMARY KEY (`id`),
KEY `idx_client` (`clientId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `multi_division_mapper` (
`parent_id` varchar(36) NOT NULL,
`division_id` varchar(36) NOT NULL,
PRIMARY KEY (`parent_id`,`division_id`),
KEY `idx_parent` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I was able to get a more favorable EXPLAIN report in a test by creating the following index:
ALTER TABLE multi_division_mapper
DROP INDEX idx_parent,
ADD INDEX (division_id, parent_id);
I also dropped idx_parent because it's redundant; it's a prefix of the primary key.
id
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra
1
SIMPLE
doc
NULL
ref
idx_client
idx_client
110
const
1
100.00
Using temporary
1
SIMPLE
divisions
NULL
ref
PRIMARY,division_id
division_id
38
const
1
100.00
Using where; Using index; Distinct
The type: ref is better than type: index.
The query I tested is slightly different, but I believe it returns the same result:
SELECT DISTINCT doc.*
FROM document doc
LEFT JOIN multi_division_mapper divisions
ON doc.id = divisions.parent_id AND divisions.division_id in ('SOME_GUID')
WHERE doc.clientId = 'SOME_GUID'

What is the best index for this two query?

I want to avoid redundant index, so what is the best composite index for these two query? Based on my understanding, these two query cannot have the same composite index since one need country, the other one need product_id, but if I make the index as below, will it be redundant index, and effect the DB performance?
combine merchant_id, created_at and product_id
combine merchant_id, created_at and country
Query 1
SELECT * from shop_order
WHERE shop_order.merchant_id = ?
AND shop_order.created_at >= TIMESTAMP(?)
AND shop_order.created_at <= TIMESTAMP(?)
AND shop_order.product_id = ?) AS mytable
WHERE product_id IS NOT NULL GROUP BY product_id, title;
Query 2
SELECT COALESCE(SUM(total_price_usd),0) AS revenue,
COUNT(*) as total_order, COALESCE(province, 'Unknown') AS name
FROM shop_order
WHERE DATE(created_at) >= '2021-02-08 13:37:42'
AND DATE(created_at) <= '2021-02-14 22:44:13'
AND merchant_id IN (18,19,20,1)
AND country = 'Malaysia' GROUP BY province;
Table structure
CREATE TABLE `shop_order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`merchant_id` bigint(20) DEFAULT NULL,
`order_id` bigint(20) NOT NULL,
`customer_id` bigint(20) DEFAULT NULL,
`customer_orders_count` varchar(45) DEFAULT NULL,
`customer_total_spent` varchar(45) DEFAULT NULL,
`customer_email` varchar(100) DEFAULT NULL,
`customer_last_order_name` varchar(45) DEFAULT NULL,
`currency` varchar(10) NOT NULL,
`total_price` decimal(20,8) NOT NULL,
`subtotal_price` decimal(20,8) NOT NULL,
`transaction_fee` decimal(20,8) DEFAULT NULL,
`total_discount` decimal(20,8) DEFAULT '0.00000000',
`shipping_fee` decimal(20,8) DEFAULT '0.00000000',
`total_price_usd` decimal(20,8) DEFAULT NULL,
`transaction_fee_usd` decimal(20,8) DEFAULT NULL,
`country` varchar(50) DEFAULT NULL,
`province` varchar(45) DEFAULT NULL,
`processed_at` datetime DEFAULT NULL,
`refunds` json DEFAULT NULL,
`ffm_status` varchar(50) DEFAULT NULL,
`gateway` varchar(45) DEFAULT NULL,
`confirmed` tinyint(1) DEFAULT NULL,
`cancelled_at` datetime DEFAULT NULL,
`cancel_reason` varchar(100) DEFAULT NULL,
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`order_number` bigint(1) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`financial_status` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `shop_order_unique` (`merchant_id`,`order_id`),
KEY `merchant_id` (`merchant_id`),
KEY `combine_idx1` (`country`,`merchant_id`,`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=2237 DEFAULT CHARSET=utf8mb4;
Please help me
Query 1:
INDEX(merchant_id, product_id, -- Put columns for "=" tests first (in any order)
created_at) -- then range
Query 2. First, avoid hiding created_at in a function call (DATE()); it prevents using it in an index.
INDEX(country, -- "="
merchant_id, -- IN
created_at) -- range (after removing DATE)
You are correct in saying that you need separate indexes for those queries. And possibly some of your existing indexes are needed for other queries.
Also, you already have a redundant index. Drop KEY merchant_id (merchant_id), -- You have ate least one other index starting with merchant_id.
Having extra indexes is only a minor performance drag. And the hit is during INSERT or if you UPDATE any column in an index. Generally, the benefit of the 'right' index to a SELECT outweighs the hit to the writes.
Having multiple unique indexes is somewhat a burden. Do you really need id since you have a "natural" PK made up of those two columns? Check to see if other tables need to join on id.
Consider shrinking many of the datasizes. BIGINT takes 8 bytes and has a range that is rarely needed. decimal(20,8) takes 10 bytes and allows up to a trillion dollars; this seems excessive, too. Is customer_orders_count a number?

Mysql JOIN query apparently slow

I have 2 tables. The first, called stazioni, where I store live weather data from some weather station, and the second called archivio2, where are stored archived day data. The two tables have in common the ID station data (ID on stazioni, IDStazione on archvio2).
stazioni (1,743 rows)
CREATE TABLE `stazioni` (
`ID` int(10) NOT NULL,
`user` varchar(100) NOT NULL,
`nome` varchar(100) NOT NULL,
`email` varchar(50) NOT NULL,
`localita` varchar(100) NOT NULL,
`provincia` varchar(50) NOT NULL,
`regione` varchar(50) NOT NULL,
`altitudine` int(10) NOT NULL,
`stazione` varchar(100) NOT NULL,
`schermo` varchar(50) NOT NULL,
`installazione` varchar(50) NOT NULL,
`ubicazione` varchar(50) NOT NULL,
`immagine` varchar(100) NOT NULL,
`lat` double NOT NULL,
`longi` double NOT NULL,
`file` varchar(255) NOT NULL,
`url` varchar(255) NOT NULL,
`temperatura` decimal(10,1) DEFAULT NULL,
`umidita` decimal(10,1) DEFAULT NULL,
`pressione` decimal(10,1) DEFAULT NULL,
`vento` decimal(10,1) DEFAULT NULL,
`vento_direzione` decimal(10,1) DEFAULT NULL,
`raffica` decimal(10,1) DEFAULT NULL,
`pioggia` decimal(10,1) DEFAULT NULL,
`rate` decimal(10,1) DEFAULT NULL,
`minima` decimal(10,1) DEFAULT NULL,
`massima` decimal(10,1) DEFAULT NULL,
`orario` varchar(16) DEFAULT NULL,
`online` int(1) NOT NULL DEFAULT '0',
`tipo` int(1) NOT NULL DEFAULT '0',
`webcam` varchar(255) DEFAULT NULL,
`webcam2` varchar(255) DEFAULT NULL,
`condizioni` varchar(255) DEFAULT NULL,
`Data2` datetime DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
archivio2 (2,127,347 rows)
CREATE TABLE `archivio2` (
`ID` int(10) NOT NULL,
`IDStazione` int(4) NOT NULL DEFAULT '0',
`localita` varchar(100) NOT NULL,
`temp_media` decimal(10,1) DEFAULT NULL,
`temp_minima` decimal(10,1) DEFAULT NULL,
`temp_massima` decimal(10,1) DEFAULT NULL,
`pioggia` decimal(10,1) DEFAULT NULL,
`pressione` decimal(10,1) DEFAULT NULL,
`vento` decimal(10,1) DEFAULT NULL,
`raffica` decimal(10,1) DEFAULT NULL,
`records` int(10) DEFAULT NULL,
`Data2` datetime DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
The indexes that I set
-- Indexes for table `archivio2`
--
ALTER TABLE `archivio2`
ADD PRIMARY KEY (`ID`),
ADD KEY `IDStazione` (`IDStazione`),
ADD KEY `Data2` (`Data2`);
-- Indexes for table `stazioni`
--
ALTER TABLE `stazioni`
ADD PRIMARY KEY (`ID`),
ADD KEY `Tipo` (`Tipo`);
ALTER TABLE `stazioni` ADD FULLTEXT KEY `localita` (`localita`);
On a map, I call by a calendar the date to search data on archive2 table, by this INNER JOIN query (I put an example date):
SELECT *, c.pioggia AS rain, c.raffica AS raff, c.vento AS wind, c.pressione AS press
FROM stazioni as o
INNER JOIN archivio2 as c ON o.ID = c.IDStazione
WHERE c.Data2 LIKE '2019-01-01%'
All works fine, but the time needed to show result are really slow (4/5 seconds), even if the query execution time seems to be ok (about 0.5s/1.0s).
I tried to execute the query on PHPMyadmin, and the results are the same. Execution time quickly, but time to show result extremely slow.
EXPLAIN query result
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE o ALL PRIMARY,ID NULL NULL NULL 1743 NULL
1 SIMPLE c ref IDStazione,Data2 IDStazione 4 sccavzuq_rete.o.ID 1141 Using where
UPDATE: the query goes fine if I remove the index from 'IDStazione'. But in this way I lost all advantages and speed on other queries... why only that query become slow if I put index on that field?
In your WHERE clause
WHERE c.Data2 LIKE '2019-01-01%'
the value of Data2 must be casted to a string. No index can be used for that condition.
Change it to
WHERE c.Data2 >= '2019-01-01' AND c.Data2 < '2019-01-01' + INTERVAL 1 DAY
This way the engine should be able to use the index on (Data2).
Now check the EXPLAIN result. I would expect, that the table order is swapped and the key column will show Data2 (for c) and ID (for o).
(Fixing the DATE is the main performance solution; here is a less critical issue.)
The tables are much bigger than necessary. Size impacts disk space and, to some extent, speed.
You have 1743 stations, yet the datatype is a 32-bit (4-byte) number (INT). SMALLINT UNSIGNED would allow for 64K stations and use only 2 bytes.
Does it get really, really, hot there? Like 999999999.9 degrees? DECIMAL(10.1) takes 5 bytes; DECIMAL(4,1) takes only 3 and allows up to 999.9 degrees. DECIMAL(3,1) has a max of 99.9 and takes only 2 bytes.
What is "localita varchar(100)" doing in the big table? Seems like you could JOIN to the stations table when you need it? Removing that might cut the table size in half.

Which column(s) to index in MySQL

I'm trying to optimize the following table, according to phpMyAdmin several stats regarding Table Scans are high and indices do not exist or are not being used. (Handler read rnd next 5.7 M)
1.
$query = "
SELECT * FROM apps_discrep
WHERE discrep_station = '$station'
AND discrep_date = '$date'
ORDER BY discrep_timestart";
2.
$query = "
SELECT * FROM apps_discrep
WHERE discrep_date BETWEEN '$keyword' AND '$keyword3'
AND (discrep_station like '$keyword2%') ORDER BY discrep_date";
Would it be correct to Index discrep_station, discrep_date, and discrep_timestart?
There currently only exist the Primary Unique Index on the auto-increment ID.
-- Table structure
`index` int(11) NOT NULL AUTO_INCREMENT,
discrep_station varchar(5) NOT NULL,
discrep_timestart time NOT NULL,
discrep_timestop time NOT NULL,
discrep_date date NOT NULL,
discrep_datetime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
discrep_show varchar(31) NOT NULL,
discrep_text text NOT NULL,
discrep_by varchar(11) NOT NULL,
discrep_opr varchar(11) NOT NULL,
email_traffic varchar(3) NOT NULL,
email_techs varchar(3) NOT NULL,
email_promos varchar(3) NOT NULL,
email_spots varchar(3) NOT NULL,
eas_row varchar(11) NOT NULL,
PRIMARY KEY (`index`)
ENGINE=MyISAM DEFAULT CHARSET=utf8;
It looks to me like you can get both queries with the same BTREE index, since that allows you to use the left-most tuples as a separate index.
Consider this MySQL doc page as a reference.
ALTER TABLE xxx ADD KEY `key1` (`discrep_station`, `discrep_date`, `discrep_timestart`) USING BTREE;
Your first query will use all 3 fields in the index. The second query will only use the first 2 fields in the index.

MySQL query optimization - index

I have these tables:
CREATE TABLE `cstat` (
`id_cstat` bigint(20) NOT NULL,
`lang_code` varchar(3) NOT NULL,
`description` varchar(255) NOT NULL,
`description_tr` varchar(255) NOT NULL,
`id_ccountry` varchar(3) NOT NULL,
`geometry_point` point DEFAULT NULL,
`geometry_poly` polygon DEFAULT NULL,
`name_type` varchar(1) NOT NULL,
`bb_min_lat` double DEFAULT NULL,
`bb_min_lon` double DEFAULT NULL,
`bb_max_lat` double DEFAULT NULL,
`bb_max_lon` double DEFAULT NULL,
`has_ex` tinyint(1) NOT NULL DEFAULT '0',
`order` int(11) DEFAULT NULL,
PRIMARY KEY (`id_cstat`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `dstat` (
`id_cstat` bigint(20) NOT NULL,
`lang_code` varchar(3) NOT NULL,
`word` varchar(30) NOT NULL,
`word_no` tinyint(3) unsigned NOT NULL,
`word_cnt` tinyint(3) unsigned NOT NULL,
`word_grp` tinyint(3) unsigned NOT NULL,
`name_type` char(1) CHARACTER SET ascii NOT NULL,
`cstat_order` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
I need to select a record from cstat using conditions from dstat and in order of cstat.order or dstat.cstat_order.
My query look like this:
SELECT cstat.ID_CSTAT, cstat.LANG_CODE, cstat.DESCRIPTION, cstat.DESCRIPTION_TR, cstat.ID_CCOUNTRY, AsBinary(cstat.GEOMETRY_POINT) AS GEOMETRY_POINT, cstat.NAME_TYPE, cstat.BB_MIN_LAT, cstat.BB_MIN_LON, cstat.BB_MAX_LAT, cstat.BB_MAX_LON, cstat.HAS_EX
FROM cstat cstat
JOIN dstat W0
ON (W0.ID_CSTAT = cstat.ID_CSTAT)
where
(W0.WORD = 'ceska') AND
(W0.NAME_TYPE = 'B')
ORDER BY W0.CSTAT_ORDER;
Can anybody help me what index to create to prevent using filesort? I believe I've tried almost everything, but I failed. There are more modifications of this base query (another one or more joins of table dstat, but thats not important right now).
Thanks a lot for your help.
EDIT: To be honest - I've tried a lot of indexes. The base one I've declared is a primary key on cstat_id_cstat. At the moment I have following indexes:
KEY `ix_dstat_nt_word_id_order` (`name_type`,`word`,`id_cstat`,`cstat_order`);
KEY `ix_dstat_word_id_order` (`word`,`id_cstat`,`cstat_order`);
KEY `ix_dstat_nt_grp_no_word_id_order` (`name_type`,`word_grp`,`word_no`,`word`,`id_cstat`,`cstat_order`);
KEY `ix_dstat_grp_no_word_id_order` (`word_grp`,`word_no`,`word`,`id_cstat`,`cstat_order`);
KEY `ix_dstat_nt_grp_word_id_order` (`name_type`,`word_grp`,`word`,`id_cstat`,`cstat_order`);
which partly solves my problem with indexed reading. But sort is always made by using filesort.
EXPLAIN
1, 'SIMPLE', 'W0', 'ref', 'ix_dstat_nt_word_id_order,ix_dstat_word_id_order,ix_dstat_nt_grp_no_word_id_ord‌​er,ix_dstat_nt_grp_word_id_order', 'ix_dstat_nt_word_id_order', '93', 'const,const', 1, 'Using where; Using index; Using filesort'
1, 'SIMPLE', 'cstat', 'eq_ref', 'PRIMARY,ix_cstat_id_order', 'PRIMARY', '8', 'search_2012_q3_cze_svk_dev.W0.id_cstat', 1, ''
looks like you should have one index on cstat.id_cstat
and one on dstat for word, and name_type
alter your table and add index on column id_cstat on table dstat
ALTER TABLE dstat ADD INDEX tb_idx(id_cstat)
so it will not require full table scan, then also on table cstat
ALTER TABLE cstat ADD INDEX tba_idx(`order`)
Problem is solved by adding following indexes:
KEY `ix_dstat_nt_word_order_id_grp_no` (`name_type`,`word`,`cstat_order`,`id_cstat`,`word_grp`,`word_no`);
KEY `ix_dstat_word_order_id_grp_no` (`word`,`cstat_order`,`id_cstat`,`word_grp`,`word_no`);