I have a rather large table (1,8GB, 25M records), with indexes on every important column (those I use WHERE or other selectors with). The engine is MyISAM, I've heard people recommend switching to InnoDB but many others said MyISAM is faster with large amounts of data in terms of counting (and InnoDB better for safe transactions).
Now, sometimes, I do a set of simple stats queries (so I see where we stand):
(A) SELECT COUNT(username) FROM superLargeTable
(B) SELECT COUNT(username) FROM superLargeTable WHERE firstname IS NOT NULL
(C) SELECT COUNT(username) FROM superLargeTable WHERE firstname IS NULL
If the table has been updated recently (and the caches are invalid), these are the query times measured by the slow query log:
A: 71 seconds (Lock:0s) (Rows:1) B: 47 seconds (Lock:0s) (Rows:1) C: 20 seconds (Lock:0s) (Rows:1)
A second run, obviously (since it's cached then) results in almost instant data.
I have indexes on all the relevant columns (pretty much on almost all of them). I still juggle with recommendations saying that indexes on many columns is very bad design, on the other hand, I totally need it since the queries would all time out otherwise.
I do have quite a few burst-type inserts and updates, firing at the table on irregular intervals (sometimes every minute, with up to 5000 inserts/updates fast-burst), sometimes with a few minutes in between.
The data needs to be in sync, so I can't split up into a read-only slave and just work with that.
Any idea why a simple COUNT takes so long? Is there a secret alternative command that tells me how many records are in a row, with a single, certain criteria?
Really puzzled. Server is an 8GHz, 8/16GB RAM, 160GB disk (10% in use or so) and the queries are all run locally and not transferred over the web.
Willing to help with more data/information if required.
Edit 1: EXPLAIN command for query A returns this:
select_type=SIMPLE
type=index
possible_keys=NULL
key=followers (this is the actual username column in the imaginary query above)
key_len=9
ref=NULL
rows=24408162
Extra=Using index
Edit 2: @theHe recommended a great tool: mysqltuner.pl – here are the results (the issues):
[!!] Total fragmented tables: 15
[!!] Maximum possible memory usage: 30.7G (767% of installed RAM)
[!!] Query cache efficiency: 8.6% (5M cached / 59M selects)
[!!] Joins performed without indexes: 19031
[!!] Temporary tables created on disk: 48% (993K on disk / 2M total)
[!!] Table cache hit rate: 0% (64 open / 27K opened)
And these are the recommendations:
-------- Recommendations -----------------------------------------------------
General recommendations:
Run OPTIMIZE TABLE to defragment tables for better performance
Reduce your overall MySQL memory footprint for system stability
Adjust your join queries to always utilize indexes
When making adjustments, make tmp_table_size/max_heap_table_size equal
Reduce your SELECT DISTINCT queries without LIMIT clauses
Increase table_cache gradually to avoid file descriptor limits
Variables to adjust:
*** MySQL's maximum memory usage is dangerously high ***
*** Add RAM before increasing MySQL buffer variables ***
query_cache_limit (> 10M, or use smaller result sets)
join_buffer_size (> 128.0K, or always use indexes with joins)
tmp_table_size (> 32M)
max_heap_table_size (> 16M)
table_cache (> 64)