Permalänk

Databas optimering

Hej

Jag har nu en väldigt stor databas som det går en del querys på, närmare sagt 135,447,767 querys på 78 dagar.
Databasen har en del tabeller, 22 för att vara exakt. Dem flesta håller bara en del "statisk" info så som kategorier etc.
Det är MySQL och MyISAM tabeller.
Men sen är det 3 tabeller som fylls med loggar och det är dem som tar tid och det jag undrar är vad som kan göras för att optimera lite här.
Jag förstår självklart att detta inte kommer vara tillräckligt med information från min sida men tänkte en generella tips

Lite information om dem 3 tabellerna.

Namn - Rader - Storlek - Kommentar
'logg_case' - 1,627,812 - 408,3 MiB - Här sparas det mesta av loggen, username, fritext, några datum, aborted totalt 12 kollumner. Många fält som har standard NULL som jag förstått inte är så bra? 7 kardinaliteter som jag inte vet riktigt hur dem fungerar, höga tal på dem iaf.

Och sen 2 tabeller för 'cat2case' och 'flagg2case' som bara binder ihop loggar med kategorier och flaggor. En case kan ha flera flaggor och kategorier.

Varje gång man ska logga något så visar den tidigare loggar på samma username/identifikator och går då genom dem 1,6 miljoner rader som 'case' består av och också 'cat2case'/'flagg2case' så det tar en del tid...

Bah känns så hopplöst att ändra på en så stor existerande databas som jag inte gjort från början!

Men igen, vad är viktigt att tänka på här, pröva få bort NULL som standard på rader? Kardinaliteten?

Permalänk

Absolut viktigast när det gäller databaser med större informationsmängd är bra definierade index. Har du redan det så får du börja med finliret...
Nästa sak är hur mycket data som måste ligga kvar i loggarna. Om man kan ha automatisk rensning av äldre data (flytta till annan tabell) så kan det underlätta mycket.

Visa signatur

Jag kan ha fel, men jag tror att jag har rätt.

Permalänk
Glömsk

EXPLAIN <din query>

Så kan du se hur queryplaneraren bestämmer sig för att köra din query.

Om du ser att du har en sekventiell scan på hela tabellen så kan du nog skapa lite index som Mattsingen säger.

Visa signatur

...man is not free unless government is limited. There's a clear cause and effect here that is as neat and predictable as a law of physics: As government expands, liberty contracts.

Permalänk
Medlem

Vi(?) vill veta hur dina tabeller ser ut :
"describe tablename;"
Mer info om storlek :
"show table status;"
Samt vad du har för server (OS,MySQL-version,CPU,RAM och disk).
Vad du har för inställningar på din MySQL.
my.cnf och eller "show variables;"

Samt naturligtvis de querys du gör mot databasen (gärna med explain)

Din databas är inte stor även om du tror det och det är ju bra

Permalänk
Skrivet av iXam:

Vi(?) vill veta hur dina tabeller ser ut :
"describe tablename;"
Mer info om storlek :
"show table status;"
Samt vad du har för server (OS,MySQL-version,CPU,RAM och disk).
Vad du har för inställningar på din MySQL.
my.cnf och eller "show variables;"

Samt naturligtvis de querys du gör mot databasen (gärna med explain)

Din databas är inte stor även om du tror det och det är ju bra

describe case; +-----------------+---------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+---------------------+------+-----+---------+----------------+ | caseid | int(11) | NO | PRI | NULL | auto_increment | | uname | varchar(25) | YES | MUL | NULL | | | serviceid | int(11) | YES | MUL | NULL | | | pid | varchar(250) | YES | MUL | NULL | | | userid | varchar(25) | YES | MUL | NULL | | | sambnr | int(11) | YES | | NULL | | | ftext | text | YES | | NULL | | | tagtext | varchar(250) | YES | | NULL | | | closed | varchar(18) | YES | MUL | NULL | | | created | varchar(18) | YES | MUL | NULL | | | aborted | varchar(18) | NO | | NULL | | | duration | int(5) | NO | MUL | NULL | | | duration_failed | tinyint(1) unsigned | NO | | 0 | | +-----------------+---------------------+------+-----+---------+----------------+

mysql> show table status; +--------------------------+--------+---------+------------+---------+----------------+-------------+-------------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-------------------+----------+----------------+-------------------+ | Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment | +--------------------------+--------+---------+------------+---------+----------------+-------------+-------------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-------------------+----------+----------------+-------------------+ | rslog_case | MyISAM | 10 | Dynamic | 1627914 | 152 | 248995296 | 281474976710655 | 179154944 | 0 | 1627974 | 2009-02-18 10:05:33 | 2012-03-04 16:25:22 | 2010-08-05 11:52:29 | utf8_general_ci | NULL | | | +--------------------------+--------+---------+------------+---------+----------------+-------------+-------------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-------------------+----------+----------------+-------------------+

mysql> show variables; +---------------------------------+---------------------------------+ | Variable_name | Value | +---------------------------------+---------------------------------+ | auto_increment_increment | 1 | | auto_increment_offset | 1 | | automatic_sp_privileges | ON | | back_log | 50 | | basedir | /usr/ | | binlog_cache_size | 32768 | | bulk_insert_buffer_size | 8388608 | | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | | collation_connection | utf8_general_ci | | collation_database | utf8_general_ci | | collation_server | utf8_general_ci | | completion_type | 0 | | concurrent_insert | 1 | | connect_timeout | 10 | | datadir | /var/lib/mysql/ | | date_format | %Y-%m-%d | | datetime_format | %Y-%m-%d %H:%i:%s | | default_week_format | 0 | | delay_key_write | ON | | delayed_insert_limit | 100 | | delayed_insert_timeout | 300 | | delayed_queue_size | 1000 | | div_precision_increment | 4 | | keep_files_on_create | OFF | | engine_condition_pushdown | OFF | | expire_logs_days | 0 | | flush | OFF | | flush_time | 0 | | ft_boolean_syntax | + -><()~*:""&| | | ft_max_word_len | 84 | | ft_min_word_len | 4 | | ft_query_expansion_limit | 20 | | ft_stopword_file | (built-in) | | group_concat_max_len | 1024 | | have_archive | NO | | have_bdb | NO | | have_blackhole_engine | NO | | have_compress | YES | | have_crypt | YES | | have_csv | NO | | have_dynamic_loading | YES | | have_example_engine | NO | | have_federated_engine | NO | | have_geometry | YES | | have_innodb | YES | | have_isam | NO | | have_merge_engine | YES | | have_ndbcluster | NO | | have_openssl | DISABLED | | have_ssl | DISABLED | | have_query_cache | YES | | have_raid | NO | | have_rtree_keys | YES | | have_symlink | YES | | hostname | tx3 | | init_connect | | | init_file | | | init_slave | | | innodb_additional_mem_pool_size | 2097152 | | innodb_autoextend_increment | 8 | | innodb_buffer_pool_awe_mem_mb | 0 | | innodb_buffer_pool_size | 16777216 | | innodb_checksums | ON | | innodb_commit_concurrency | 0 | | innodb_concurrency_tickets | 500 | | innodb_data_file_path | ibdata1:10M:autoextend:max:128M | | innodb_data_home_dir | | | innodb_adaptive_hash_index | ON | | innodb_doublewrite | ON | | innodb_fast_shutdown | 1 | | innodb_file_io_threads | 4 | | innodb_file_per_table | ON | | innodb_flush_log_at_trx_commit | 1 | | innodb_flush_method | | | innodb_force_recovery | 0 | | innodb_lock_wait_timeout | 50 | | innodb_locks_unsafe_for_binlog | OFF | | innodb_log_arch_dir | | | innodb_log_archive | OFF | | innodb_log_buffer_size | 8388608 | | innodb_log_file_size | 5242880 | | innodb_log_files_in_group | 2 | | innodb_log_group_home_dir | ./ | | innodb_max_dirty_pages_pct | 90 | | innodb_max_purge_lag | 0 | | innodb_mirrored_log_groups | 1 | | innodb_open_files | 300 | | innodb_rollback_on_timeout | OFF | | innodb_support_xa | ON | | innodb_sync_spin_loops | 20 | | innodb_table_locks | ON | | innodb_thread_concurrency | 8 | | innodb_thread_sleep_delay | 10000 | | interactive_timeout | 28800 | | join_buffer_size | 131072 | | key_buffer_size | 2147483648 | | key_cache_age_threshold | 300 | | key_cache_block_size | 1024 | | key_cache_division_limit | 100 | | language | /usr/share/mysql/english/ | | large_files_support | ON | | large_page_size | 0 | | large_pages | OFF | | lc_time_names | en_US | | license | GPL | | local_infile | ON | | locked_in_memory | OFF | | log | OFF | | log_bin | ON | | log_bin_trust_function_creators | OFF | | log_error | /var/log/mysql/mysqld.err | | log_queries_not_using_indexes | OFF | | log_slave_updates | OFF | | log_slow_queries | OFF | | log_warnings | 1 | | long_query_time | 10 | | low_priority_updates | OFF | | lower_case_file_system | OFF | | lower_case_table_names | 0 | | max_allowed_packet | 1048576 | | max_binlog_cache_size | 18446744073709547520 | | max_binlog_size | 1073741824 | | max_connect_errors | 10 | | max_connections | 100 | | max_delayed_threads | 20 | | max_error_count | 64 | | max_heap_table_size | 16777216 | | max_insert_delayed_threads | 20 | | max_join_size | 18446744073709551615 | | max_length_for_sort_data | 1024 | | max_prepared_stmt_count | 16382 | | max_relay_log_size | 0 | | max_seeks_for_key | 18446744073709551615 | | max_sort_length | 1024 | | max_sp_recursion_depth | 0 | | max_tmp_tables | 32 | | max_user_connections | 0 | | max_write_lock_count | 18446744073709551615 | | multi_range_count | 256 | | myisam_data_pointer_size | 6 | | myisam_max_sort_file_size | 9223372036853727232 | | myisam_recover_options | OFF | | myisam_repair_threads | 1 | | myisam_sort_buffer_size | 8388608 | | myisam_stats_method | nulls_unequal | | net_buffer_length | 8192 | | net_read_timeout | 30 | | net_retry_count | 10 | | net_write_timeout | 60 | | new | OFF | | old_passwords | OFF | | open_files_limit | 1024 | | optimizer_prune_level | 1 | | optimizer_search_depth | 62 | | pid_file | /var/run/mysqld/mysqld.pid | | plugin_dir | | | port | 3306 | | preload_buffer_size | 32768 | | protocol_version | 10 | | query_alloc_block_size | 8192 | | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 0 | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | | query_prealloc_size | 8192 | | range_alloc_block_size | 4096 | | read_buffer_size | 262144 | | read_only | OFF | | read_rnd_buffer_size | 524288 | | relay_log | | | relay_log_index | | | relay_log_info_file | relay-log.info | | relay_log_purge | ON | | relay_log_space_limit | 0 | | rpl_recovery_rank | 0 | | secure_auth | OFF | | secure_file_priv | | | server_id | 1 | | skip_external_locking | ON | | skip_networking | OFF | | skip_show_database | OFF | | slave_compressed_protocol | OFF | | slave_load_tmpdir | /tmp/ | | slave_net_timeout | 3600 | | slave_skip_errors | OFF | | slave_transaction_retries | 10 | | slow_launch_time | 2 | | socket | /var/run/mysqld/mysqld.sock | | sort_buffer_size | 524288 | | sql_big_selects | ON | | sql_mode | | | sql_notes | ON | | sql_warnings | OFF | | ssl_ca | | | ssl_capath | | | ssl_cert | | | ssl_cipher | | | ssl_key | | | storage_engine | MyISAM | | sync_binlog | 0 | | sync_frm | ON | | system_time_zone | CET | | table_cache | 64 | | table_lock_wait_timeout | 50 | | table_type | MyISAM | | thread_cache_size | 0 | | thread_stack | 262144 | | time_format | %H:%i:%s | | time_zone | SYSTEM | | timed_mutexes | OFF | | tmp_table_size | 33554432 | | tmpdir | /tmp/ | | transaction_alloc_block_size | 8192 | | transaction_prealloc_size | 4096 | | tx_isolation | REPEATABLE-READ | | updatable_views_with_limit | YES | | version | 5.0.70-log | | version_comment | Gentoo Linux mysql-5.0.70-r1 | | version_compile_machine | x86_64 | | version_compile_os | pc-linux-gnu | | wait_timeout | 28800 | +---------------------------------+---------------------------------+

Haha shit, det blev mycket. Men detta var det du fråga efter? OS etc står i show variables.

Angående server hårdvaran så är det nog inge problem, osäker på hur jag får fram det via terminalen men det är en bladserver som står i källaren i bygget här iaf

Permalänk
Medlem

Finemang. Hur ser en exempelrad i databasen ut? Och gärna en exempelquery som tar lång tid.

Permalänk
Skrivet av iXam:

Finemang. Hur ser en exempelrad i databasen ut? Och gärna en exempelquery som tar lång tid.

Ska försöka fixa ett fint exempel snart men i mellantiden så har jag fått nya problem, först så steg Opened_tables väldigt snabbt men det fixade jag med att höja table_cache.

Men det andra är att Handler_read_rnd_next också höjs sjukt snabbt och till slut måste jag starta om mysql servern... har inte ändrat någon kod som kör querys och har fungerat fint förut.

Dem queryes jag kör har Type = REF och Rows ~1000 vilket borde vara OK?

Finns det något i confen jag kan ändra för att få ned Handler_read_rnd_next?

Exempel på tung query:

EXPLAIN SELECT c.caseid, c.uname, c.pid, c.sambnr, c.ftext, c.tagtext, c.created, c.closed, c.aborted, s.servicename, c.userid, u.fname, u.lname, c.serviceid, c.duration, COUNT(t.id) AS tbv, v.key AS verdikodekey, v.description AS verdikodetext FROM rslog_case c LEFT JOIN rscore_user u ON (c.userid = u.userid) LEFT JOIN rslog_service s ON (c.serviceid = s.serviceid) LEFT JOIN verdikode v ON (c.caseid = v.caseid) LEFT JOIN rslog_tbv t ON c.caseid = t.caseid WHERE c.pid LIKE "%NULL%" OR c.uname LIKE "%NULL%" OR c.ftext LIKE "%NULL%" GROUP BY c.caseid ORDER BY c.caseid DESC LIMIT 40; +----+-------------+-------+--------+---------------+-----------+---------+-----------------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+-----------+---------+-----------------+---------+-------------+ | 1 | SIMPLE | c | index | NULL | PRIMARY | 4 | NULL | 1628428 | Using where | | 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 92 | dev.c.userid | 1 | | | 1 | SIMPLE | s | eq_ref | PRIMARY | PRIMARY | 4 | dev.c.serviceid | 1 | | | 1 | SIMPLE | v | ref | idx_vkode | idx_vkode | 4 | dev.c.caseid | 119 | | | 1 | SIMPLE | t | ref | caseid | caseid | 4 | dev.c.caseid | 1 | | +----+-------------+-------+--------+---------------+-----------+---------+-----------------+---------+-------------+

Inte jag som skrivit förfrågningarna från början, ville bara säga det

Permalänk
Medlem

Jag är mest van vid MSSQL, men kan försöka ge ett par tips ändå eftersom mysql-experterna verkar tagit paus
1. Testa o ta bort joinarna och se om frågan går lika trögt eller om det hjälper. Fortfarande trögt? Då vet du att det är rslog_case och det blir enklare att söka vidare eftersom du begränsat optimeringen till en enkel select
2. Misstänker att det är where-satsen som är boven, att rslog_case inte är idexerad på pid, uname eller ftext. Har du möjligthet att testa utan att det gör något så lägg till ett index på var och en av dom och se om det hjälper (förutsatt att dom inte redan är med i ett index förståss).
3. Ibland hjälper det att strukturera om frågan. Tex bryta ut till en subquery eller dela upp queryn i två där första delen sparar sitt svar i en variabel som används i andra delen. Men det är svårt att se på rak arm utan att veta mer vad som är trögt. Första steget är att lista ut vilken del som gör frågan seg.

Permalänk
Medlem

Snabbis innan jag lägger mig.
LIKE "%NULL%" kan inte använda index utan resulterar i en full table scan.

Permalänk
Skrivet av vb:

Jag är mest van vid MSSQL, men kan försöka ge ett par tips ändå eftersom mysql-experterna verkar tagit paus
1. Testa o ta bort joinarna och se om frågan går lika trögt eller om det hjälper. Fortfarande trögt? Då vet du att det är rslog_case och det blir enklare att söka vidare eftersom du begränsat optimeringen till en enkel select
2. Misstänker att det är where-satsen som är boven, att rslog_case inte är idexerad på pid, uname eller ftext. Har du möjligthet att testa utan att det gör något så lägg till ett index på var och en av dom och se om det hjälper (förutsatt att dom inte redan är med i ett index förståss).
3. Ibland hjälper det att strukturera om frågan. Tex bryta ut till en subquery eller dela upp queryn i två där första delen sparar sitt svar i en variabel som används i andra delen. Men det är svårt att se på rak arm utan att veta mer vad som är trögt. Första steget är att lista ut vilken del som gör frågan seg.

Jo får bli till att sitta och leta upp den tröga förfrågningen och försöka skriva om dem.

Skrivet av iXam:

Snabbis innan jag lägger mig.
LIKE "%NULL%" kan inte använda index utan resulterar i en full table scan.

Du menar att LIKE inte använder index? Det var ju inte så bra då... vet inte hur jag ska fixa det dock, vill ju få upp liknande loggar när man skriver i fälten för t.ex. fritext och username. Något förslag på ändring?

Permalänk
Medlem

MySQL kan använda index för LIKE operatorn fram till första wildcardet. dvs om du ställer en LIKE fråga som inte börjar med ett wilcard så kommer du få bättre prestanda. så LIKE NULL% går fort medans LIKE %NULL går sakta.
Om man klurar lite så förstår man varför det fungerar såhär. Ett index är ju bara en sortering tex som orden i en ordlista. Det är lätt att hitta alla ord som börjar på NULL (frågan LIKE NULL%) medans det är väldigt svårt att hitta alla ord som inehåller NULL ( LIKE %NULL%).

du kan läsa mer här: http://dev.mysql.com/doc/refman/5.1/en/mysql-indexes.html

Permalänk

jo precis, det är ju faktiskt logiskt. möjligt att jag inte tappar så mycket funktionalitet av att ändra till NULL%, iaf inte på pid och username, fritext fältet vill jag ju fortfarande ha %LIKE% på då, kanske finns något annat alternativ?

Permalänk
Skrivet av python_ormen:

jo precis, det är ju faktiskt logiskt. möjligt att jag inte tappar så mycket funktionalitet av att ändra till NULL%, iaf inte på pid och username, fritext fältet vill jag ju fortfarande ha %LIKE% på då, kanske finns något annat alternativ?

Om du ofta måste göra denna typ av frågor kan det vara värt att schedulera en uppdate sats som skriver in en flagga på alla som har %NULL% eller om det är möjligt att göra per rad vid commit. Den flaggan kan indexeras. Detta kräver dock att uppdateringarna är mindre frekventa än sökningarna annars är risken att du förlora prestanda.

Visa signatur

Jag kan ha fel, men jag tror att jag har rätt.

Permalänk
Medlem

Är inte helt säker på om jag förstår syftet med like-uttrycken och om det blir som man har tänkt. Har inte satt i mig i trådskaparens problem av lathet men sneglade på konversationen.

u.username LIKE '%NULL%' låter ju knepigt. Alltså söker man ut något med ett username som innehåller texten NULL i sig? Man borde kunna ställa till lite oreda i den logiken genom att ha det med i sitt användarnamn då.

p.id låter ju numeriskt också vilket låter helt tokigt att göra en like med (och att mysql ens tillåter det är ju knepigt i sig).

Lösa reflektioner

//C

Permalänk
Medlem

borde inte raden

WHERE c.pid LIKE "%NULL%" OR c.uname LIKE "%NULL%" OR c.ftext LIKE "%NULL%"

bara bytas mot

WHERE c.pid IS NULL OR c.uname IS NULL OR c.ftext IS NULL

?

säger som @conio att jag inte läst tråden så noga, men håller med hen om att det låter underligt att söka efter grejjer som innehåller strängen NULL.

Visa signatur

as far as we can tell, the massacre went well...

Permalänk

Det är såklart inte NULL som sökes efter utan det som användaren skriver in, och vill anledningen till %username% är att man ska finna tidigare loggar på username / pid som är ett nummer ja och fritext så man finner allt som är relevant. till exempel om man har delar av ett username så ska man finna den iaf, men just pid och username kan jag nog ändra till NULL% = så man sökert på use... och finner username för det är inte så ofta man skriver ...name för att finna username. kanske är lite otydlig

Permalänk
Medlem

aha! då är jag med! tyckte väl det var lite underligt.

Visa signatur

as far as we can tell, the massacre went well...

Permalänk
Medlem

måste det sökas i en fet text kanske ett fulltext-index skulle hjälpa?