Can someone help me understand the key structure of this MySQL table? - mysql

We have a 3 column table which I did not set up that basically just tracks timestamps. Here is that table:
| Field | Type | Null | Key | Default | Extra |
| name | varchar(255) | YES | MUL | NULL | |
| type | enum('start','end') | YES | | NULL | |
| time | datetime | YES | MUL | NULL | |
Here is some sample data:
| updateIDXfiletrans.php | start | 2011-02-16 00:30:01 |
| morningmarketingimportstart.php | start | 2011-02-16 00:30:01 |
| updateIDXfiletrans.php | end | 2011-02-16 00:30:02 |
| morningmarketingimportstart.php | end | 2011-02-16 00:35:15 |
As you can see, none of the fields themselves are unique. In fact, the only logical key structure for this table would be a multi-column key for all 3 columns, because that is the only thing that should be unique, the combination of all 3. And this is what I assumed that the table had, because well... it's been working for like 3 years straight, so I didn't think the keys were set up wrong.
And then upon moving to a new server it repeatedly gets this error when we try to run imports:
ERROR 1062 (23000) at line 51: Duplicate entry 'eod_blf-start' for key
'nameindex'
I went to check the index structure and this is what I found:
| Table | Non_unique | Key_name | Seq_in_index |
Column_name | Collation | Cardinality | Sub_part | Packed | Null |
Index_type | Comment | Index_comment |
| blfimporttracking | 1 | nameindex | 1 | name
| A | 48 | NULL | NULL | YES | BTREE |
| |
| blfimporttracking | 1 | nameindex | 2 | type
| A | 96 | NULL | NULL | YES | BTREE |
| |
| blfimporttracking | 1 | timeindex | 1 | time
| A | 16920 | NULL | NULL | YES | BTREE |
| |
Everything is the same on the old server and new server, yet only the new server is having the issue. And I should also note that on each server we have the same set-up for three different companies (I double checked it today) and this is only happening on the one company's imports.
Basically, I don't understand what I'm looking at here. Are nameindex and timeindex keys, or just indexes? Whatever the case, should the way things are set up be causing a duplicate entry error?
For the heck of it I went into MySQL itself and just inserted the same data into the table in question multiple times and it all took fine. So I'm very confused here.

Related

How to pull a large amount of data from mariadb in a fast manner when workload is IO bound

Important to know information:
We have a database table 'cdrs'
+-----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+----------------+
| id | bigint(12) | NO | PRI | NULL | auto_increment |
| server_id | tinyint(2) | NO | | 0 | |
| cdr_id | bigint(13) | NO | MUL | 0 | |
| user_id | int(11) | NO | MUL | 0 | |
| transaction_id | int(11) | YES | MUL | NULL | |
| sip_id | int(11) | NO | MUL | 0 | |
| call_type | tinyint(2) | YES | MUL | NULL | |
| did_from | char(24) | YES | | NULL | |
| did_from_alias | bigint(18) | YES | MUL | 0 | |
| did_to | char(24) | YES | | NULL | |
| did_to_alias | bigint(18) | YES | MUL | 0 | |
| call_status | char(12) | YES | MUL | NULL | |
| start_time | int(11) | NO | PRI | 0 | |
| duration | decimal(13,3) | YES | | NULL | |
| billed_duration | decimal(13,3) | NO | | 0.000 | |
| rate | decimal(10,4) | YES | | NULL | |
| amount | decimal(10,4) | YES | | NULL | |
| usf | decimal(10,4) | YES | | NULL | |
| total | decimal(10,4) | YES | MUL | NULL | |
| country | varchar(96) | YES | | NULL | |
| country_id | int(8) | NO | | 0 | |
| code | varchar(8) | NO | | | |
+-----------------+---------------+------+-----+---------+----------------+
With the following indexes
+---------+------------+------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Ignored |
+---------+------------+------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
| cdrs | 0 | PRIMARY | 1 | id | A | 573346816 | NULL | NULL | | BTREE | | | NO |
| cdrs | 0 | PRIMARY | 2 | start_time | A | 573346816 | NULL | NULL | | BTREE | | | NO |
| cdrs | 1 | i_cdr_id | 1 | cdr_id | A | 573346816 | NULL | NULL | | BTREE | | | NO |
| cdrs | 1 | i_user_id | 1 | user_id | A | 158909 | NULL | NULL | | BTREE | | | NO |
| cdrs | 1 | i_call_type | 1 | call_type | A | 19887 | NULL | NULL | YES | BTREE | | | NO |
| cdrs | 1 | i_transaction_id | 1 | transaction_id | A | 143336704 | NULL | NULL | YES | BTREE | | | NO |
| cdrs | 1 | i_total | 1 | total | A | 163953 | NULL | NULL | YES | BTREE | | | NO |
| cdrs | 1 | i_start_time | 1 | start_time | A | 24928122 | NULL | NULL | | BTREE | | | NO |
| cdrs | 1 | i_call_status | 1 | call_status | A | 9877 | NULL | NULL | YES | BTREE | | | NO |
| cdrs | 1 | i_sip_id | 1 | sip_id | A | 353481 | NULL | NULL | | BTREE | | | NO |
| cdrs | 1 | i_did_to | 1 | did_to_alias | A | 286673408 | NULL | NULL | YES | BTREE | | | NO |
| cdrs | 1 | i_did_from | 1 | did_from_alias | A | 57334681 | NULL | NULL | YES | BTREE | | | NO |
+---------+------------+------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
The Problem:
Currently in production this table has more rows then the max value of int(hence why the id is bigint)
This table grows in size everyday by GB and as the company expects to grow those GB will turn into 10s of GB and eventually hundreds of GB
Right now the database is running on raid 10 SSD's
Taking the following scenario
Its the first of the month and a customer wants to pull his records for last month so he can bill his customer.
This query will be directly IO bound because none of the data will exist in the Innodb buffer because this is the first time it is queried.
So lets say our query looks similar to
SELECT * FROM cdrs WHERE user_id='<SOME_USER_ID' AND start_time>=1654099200 AND start_time<1656691200
So we are grabbing all the call records for this user from the beginning of the month to the end of the month
In a test this resulted in 52,627,431 rows for one client and took 50 seconds to just run the query
SELECT Count(*) FROM cdrs WHERE user_id='<SOME_USER_ID>' AND start_time>=1654099200 AND start_time<1656691200;
I have looked around for different databases and I just don't know what direction I need to go in but we need the ability to pull these records in a much faster fashion currently just pulling an hour of records takes 30mins for some customers with higher volumes
Possible solutions that we have tried
Use a summary table
I know one suggestion will be using a summary table which we already use one but it does not help in this instance because customers need the actual data contained in this table
Partition the table
We partition the table by the month and the results are still to slow
I have tried to use a columnstore engine in mariadb and this actually gave us significant performance improvements in some areas but not specifically for getting the CDR's to our customers
I wish I could use Redis for this because Redis is lightning fast but tables take up 1.1T of data currently and will only continue to grow
Eager and open for a solution
PRIMARY KEY
WHERE user_id='<SOME_USER_ID>'
AND start_time>=1654099200
AND start_time< 1656691200;
is best handled by
PRIMARY KEY(user_id, start_time) -- in this order.
If a "user" can have two rows with exactly the same start_time, then
PRIMARY KEY(user_id, start_time, id) -- in this order.
INDEX(id)
Otherwise, consider getting rid of id.
Having the PK start with user_id puts all the rows for a given user clustered together, making that (and similar) queries faster.
Having the second part of the PK be start_time significantly helps with that BETWEEN.
PARTITION -- There are many "wrong" ways to use PARTITIONing. To discuss that, please provide more details. In general, Partitioning does not provide any speedup.
The main reason I see for using PARTITIONing is if you need to delete "old" data; DROP PARTITION is immensely faster than DELETEing millions of rows.
Data size
Many of the comments I will make here relate to how much disk space the table is/will take.
By "clustering" the data properly, I/O is decreased when the table is much bigger than RAM. What is the setting of innodb_buffer_pool_size? How much RAM do you have? How many GB will the table have before you start purging it?
Clustering may give you 10x speedup.
CHAR -- This is a fixed length datatype; it should be used only if the data is 'always' the length specified. Otherwise, it wastes space.
INDEXes -- Don't blindly add indexes for lots of columns. Only have the ones you need. "Need" comes from the queries you will be running. Consider using "composite" indexes where appropriate.
It seems like most SELECTs would include WHERE user_id = ...; if that is correct, I would expect many of the indexes to be "composite", starting with user_id.
Country -- Don't include a 4-byte INT and a multibyte string; simply have a CHAR(2) for the standard "country_code" and, if needed, a lookup table to map to strings.
Midnight -- When building a daily or monthly report, what should happen to a call that spills across midnight?
Summary tables -- A summary table should have worked quite well for your data. Please explain what data the report needs; I'll help redesign the summary table.
If the summary is all details for all calls for the month, then that is not a "summary"; the clustered PK gives you a 10x improvement.
If "summary" means daily subtotals, then let's see the details.
Numeric types -- INT takes 4 bytes; BIGINT takes 8 bytes. The "13" in bigint(13) has no meaning. If the value is really limited to 13 digits, then consider DECIMAL(13,0), which takes 6 bytes. See also MEDIUMINT and SMALLINT. DECIMAL(13,3) takes 7 bytes.
ENGINE -- Do use InnoDB.

"Duplicate entry" even though the column has UNIQUE constraint

I'm trying to drop some columns which I'm no longer using in my table. I've got a single column with a UNIQUE constraint. When I'm trying to drop the columns I'm getting a "Duplicate entry" found for this column.
When I search for rows with this code I'm only returned with a single result, but I figure that might be because it stops looking when it finds the first (as it thinks its unique).
I've tried deleting the row in question, but after trying to delete columns I'm returned with a new code that is "Duplicate entry".
Error when trying to delete columns:
ALTER TABLE attacktable DROP COLUMN fairfightparsed, DROP COLUMN defenderbattlestatssum, DROP COLUMN attackerbsstd, DROP COLUMN defenderdsstd, DROP COLUMN defenderlevel;
ERROR 1062 (23000): Duplicate entry 'e3cce98b6aa8085ed6a960d2afcd4dca' for key 'attacktable.attackcode'
Only one of the selected attackcode:
SELECT * FROM attacktable WHERE attackcode = "e3cce98b6aa8085ed6a960d2afcd4dca";
+----------------------------------+------------+ ...
| attackcode | attackerid | ...
+----------------------------------+------------+ ...
| e3cce98b6aa8085ed6a960d2afcd4dca | 2618403 | ...
+----------------------------------+------------+ ...
1 row in set (0,00 sec)
Description of uniqueness:
describe attacktable;
+------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+-------+
| attackcode | varchar(255) | YES | UNI | NULL | |
| attackerid | int | YES | MUL | NULL | |
....
Indexes on the table:
SHOW INDEX FROM attacktable;
+-------------+------------+------------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------------+------------+------------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| attacktable | 0 | attackcode | 1 | attackcode | A | 1022111 | NULL | NULL | YES | BTREE | | | YES | NULL |
| attacktable | 1 | attackerid | 1 | attackerid | A | 2281 | NULL | NULL | YES | BTREE | | | YES | NULL |
| attacktable | 1 | resmodchain | 1 | resmodchain | A | 92 | NULL | NULL | YES | BTREE | | | YES | NULL |
| attacktable | 1 | resmodfair | 1 | resmodfair | A | 202 | NULL | NULL | YES | BTREE | | | YES | NULL |
| attacktable | 1 | resmodwar | 1 | resmodwar | A | 1 | NULL | NULL | YES | BTREE | | | YES | NULL |
| attacktable | 1 | attackerbattlestatssum | 1 | attackerbattlestatssum | A | 76782 | NULL | NULL | YES | BTREE | | | YES | NULL |
+-------------+------------+------------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
I'm now worried there are a lot of these duplicates in my table.. Help please :)
EDIT: SO I suspect it's the error-code that is wrong, not that I have duplicates. That would be easier I guess.
DELETE FROM attacktable WHERE attackcode = "e3cce98b6aa8085ed6a960d2afcd4dca";
Query OK, 1 row affected (0,02 sec)
SELECT * FROM attacktable WHERE attackcode = "e3cce98b6aa8085ed6a960d2afcd4dca";
Empty set (0,00 sec)
Solved it after finding this thread.
In my case it was caused due to continued writing to the table while I was trying to drop columns. I locked the table, dropped the columns and unlocked the tables again.
LOCK TABLE attacktable WRITE;
ALTER TABLE DROP COLUMN ...;
UNLOCK TABLES

mysql need to run optimize every day after batch jobs

I have a table with about 4M rows. Every night, about 15 batch jobs run on the data, with a few hundred thousand inserts and updates. The problem is, when I run a simple count query such as
select count(*) from items;
I have to wait for about 15 minutes for it to return. After researching on SO, I see that
optimize table items;
does seem to fix the problem, after running it, the above query returns instantly. The problem is, it takes 17 hours to run. Any suggestions on what to look for to figure out why this is happening and how to fix it?
Thanks for any help,
Kevin
UPDATE:
Here's what happens when I optimize:
mysql> optimize table items;
+------------------------+----------+----------+-------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+------------------------+----------+----------+-------------------------------------------------------------------+
| g_production.items | optimize | note | Table does not support optimize, doing recreate + analyze instead |
| g_production.items | optimize | status | OK |
+------------------------+----------+----------+-------------------------------------------------------------------+
2 rows in set (9 hours 20 min 48.36 sec)
Also, strangely, the select is not using the primary index, ID:
explain select count(id) from items;
+----+-------------+-------+-------+---------------+--------------------------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------------------- +---------+------+----------+-------------+
| 1 | SIMPLE | items | index | NULL | index_items_on_real_sale | 2 | NULL | 45152757 | Using index |
+----+-------------+-------+-------+---------------+--------------------------+---------+------+----------+-------------+
1 row in set (0.10 sec)
And finally, here are all the indexes on the table:
+-------+------------+---------------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+---------------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| items | 0 | PRIMARY | 1 | id | A | 47144790 | NULL | NULL | | BTREE | | |
| items | 1 | index_items_on_affiliate_id | 1 | affiliate_id | A | 47144790 | NULL | NULL | YES | BTREE | | |
| items | 1 | index_items_on_brand_id | 1 | brand_id | A | 1024886 | NULL | NULL | YES | BTREE | | |
| items | 1 | index_items_on_real_sale | 1 | real_sale | A | 18 | NULL | NULL | YES | BTREE | | |
| items | 1 | index_items_on_retailer_id_and_affiliate_id | 1 | retailer_id | A | 18 | NULL | NULL | YES | BTREE | | |
| items | 1 | index_items_on_retailer_id_and_affiliate_id | 2 | affiliate_id | A | 47144790 | NULL | NULL | YES | BTREE | | |
| items | 1 | index_items_on_retailer_id | 1 | retailer_id | A | 40021 | NULL | NULL | YES | BTREE | | |
| items | 1 | index_items_on_shopzilla_id | 1 | shopzilla_id | A | 457716 | NULL | NULL | YES | BTREE | | |
| items | 1 | index_items_on_updated_at | 1 | updated_at | A | 6734970 | NULL | NULL | | BTREE | | |
Note the cardinality on the index that the EXPLAIN is revealing, I have 4M rows, but explain says it's using index_items_on_real_sale, which the show indexes command reveals has a cardinality of 18. Could this be the problem?
It could be quite a few things, but I'm wondering if it's indexed properly. Also, try to run the query with explain, like so:
EXPLAIN SELECT a,b,c WHERE....
Look at the output and see how many rows it's reading to process the query and they type of indexes etc...
Definitely need more information in order to help out, I'm just guessing based on the limited information you provided.

MySQL best index for static table

I have the following table (T) in Mysql:
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| first | varchar(50) | NO | PRI | NULL | |
| second | varchar(50) | NO | PRI | NULL | |
| third | varchar(50) | NO | PRI | NULL | |
| count | bigint(20) | NO | | NULL | |
+--------+-------------+------+-----+---------+-------+
This table contains several million rows. I have created the following indices:
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| T | 0 | PRIMARY | 1 | first | A | 591956 | NULL | NULL | | BTREE | | |
| T | 0 | PRIMARY | 2 | second | A | 67927032 | NULL | NULL | | BTREE | | |
| T | 0 | PRIMARY | 3 | third | A | 271708128 | NULL | NULL | | BTREE | | |
| T | 1 | SECONDARY | 1 | second | A | 398399 | NULL | NULL | | BTREE | | |
| T | 1 | SECONDARY | 2 | third | A | 45284688 | NULL | NULL | | BTREE | | |
| T | 1 | SEC | 1 | second | A | 4382389 | NULL | NULL | | BTREE | | |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
Searches of the type:
SELECT * FROM T WHERE first = "WHAT" AND third = "EVER";
and
SELECT * FROM T WHERE first = "WHAT" AND second = "EVER";
also usually fast (results are always obtained under 1 second). However the searches like:
SELECT * FROM T WHERE second = "WHAT" AND third = "EVER";
are very slow (usually more than 1 minute). I created the index SEC (see indices table), but that doesn't improve the results.
What index should I use to make these searches faster? (I haven't kept experimenting because the creation of one index takes around 5 hours)
MORE INFO: The table is static (i.e. I won't be adding any more rows - I am only interested in search speed), and disk space is not an issue.
Use additional indexes comprising of fields which match your queries. If the row combinations are unique then use primary indexes. These give quicker access than secondary indexes.
As the table is static - the number of indexes will not affect performance (any updates, deletions and insertions require updates to each index of a table).
So for quicker retrieval from this query create an index of second and third columns:
ALTER TABLE T ADD PRIMARY KEY (second, third);

MySQL index causes queries to become slow

I have a MySQL table with some 20 million rows of data in it.
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| b_id | int(11) | YES | MUL | NULL | |
| order | bigint(20) | YES | MUL | NULL | |
| date | date | YES | | NULL | |
| time | time | YES | | NULL | |
| channel | varchar(8) | YES | MUL | NULL | |
| data | varchar(60) | YES | | NULL | |
| date_system | date | YES | MUL | NULL | |
| time_system | time | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
I had an non unique index on (b_id, channel, date) to speed up queries like:
select date, left(time,2) as hour, round(data,1) as data
from data_lines
where channel='1'
and b_id='300'
and date >='2013-04-19'
and date <='2013-04-26'
group by date,hour
The problem was that my inserts sometimes overlap, so I wanted to use 'ON DUPLICATE KEY UPDATE', however this needs a unique index. So I create a unique index on (b_id, channel, date, time) as these are the four main characteristics to determine if there is a double value. The inserts now work fine, however my select queries are unacceptable slow.
I'm not quite sure why my selects have become slower since the addition of the new index:
is time so unique that the index becomes very large --> and slow?
should I remove the non unique index to speed things up?
is it my bad querying?
other ideas welcome!
For the record (order, date_system and time_system) are not used at all in indexes or selects, but do contain data. The inserts are run from C and Python and the selects from PHP.
Per request the explain query:
mysql> explain select date, left(time,2) as hour, round(data,1) as data
from data_lines
where channel='1'
and b_id='300'
and date >='2013-04-19'
and date <='2013-04-26'
group by date,hour;
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+
| 1 | SIMPLE | data_lines| ref | update_index,b_id,comp_index | comp_index | 16 | const,const | 3548 | Using where; Using temporary; Using filesort |
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+
The update_index is my unique index of (b_id, channel, date, time) and the comp_index is my non unique index of (b_id, channel, date).
Indexes are:
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| data_lines| 0 | PRIMARY | 1 | id | A | 17918898 | NULL | NULL | | BTREE | | |
| data_lines| 0 | id_UNIQUE | 1 | id | A | 17918898 | NULL | NULL | | BTREE | | |
| data_lines| 0 | update_index | 1 | channel | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 0 | update_index | 2 | b_id | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 0 | update_index | 3 | date | A | 44244 | NULL | NULL | YES | BTREE | | |
| data_lines| 0 | update_index | 4 | time | A | 17918898 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | box_id | 1 | b_id | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | idx | 1 | order | A | 17918898 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | comp_index | 1 | b_id | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | comp_index | 2 | channel | A | 6624 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | comp_index | 3 | date | A | 165915 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | date_system | 1 | date_system | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | mac | 1 | mac | A | 17 | NULL | NULL | YES | BTREE | | |
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
Try explicitly specifying USE INDEX(update_index) in your query.
the optimizer is making wrong choice in selecting in selecting the index because of which the query is becoming slow.
Hope this solves your problem.. :)
Since a PRIMARY KEY is a UNIQUE KEY, get rid of the useless UNIQUE(id).
Are any of the columns we are talking about ever NULL? If not, make them NOT NULL. (This is important before upgrading the UNIQUE index.)
Unless you need it for some other query, DROP comp_index. It provides no extra benefit (toward your INSERT or SELECT) over the 4-column unique_index.
Do you use id anywhere else? If not, promote the 4-col unique index to be PRIMARY KEY. This step is likely to speed things up because now it is not bouncing back and forth between the index and the data (to get data).
That leaves 4 other indexes; see if you really need them. (I suggest this because a previous step will make secondary indexes bulkier.)
Change to InnoDB if you are using MyISAM.
When doing lots of ALTERs, do them in a single statement -- it will be a lot faster.
ALTER TABLE ...
DROP COLUMN id,
DROP PRIMARY KEY,
DROP INDEX `id_UNIQUE`,
DROP INDEX comp_index,
ADD PRIMARY KEY(channel, b_id, date, time),
ALTER COLUMN ... NOT NULL,
...
ENGINE=InnoDB;
Or, to be more cautious: CREATE the modified table, then INSERT...SELECT to populate it. Then test. Eventually do RENAME TABLE to put it into place.
It is usually a bad idea to split date and time into two columns instead of having a single datetime. But I won't push it, since it probably does not affect this Question much.