Merge branch 'tuning' into 'master'

Docs: Sql Tuning and python version comparison

See merge request allianceauth/allianceauth!1545
This commit is contained in:
Ariel Rin 2023-12-02 01:31:52 +00:00
commit a8ef844fe7
4 changed files with 838 additions and 0 deletions

View File

@ -14,4 +14,6 @@ The official installation guide will install a stable version of Alliance Auth t
gunicorn
celery
redis
python
sql
```

View File

@ -0,0 +1,633 @@
# Python
## Version Update
Newer versions of python can focus heavily on performance improvements, some more than others. But be aware regressions for stability or security reasons may always be the case.
As a general rule, Python 3.9 and Python 3.11 both had a strong focus on performance improvements. Python 3.12 is looking promising but has yet to have widespread testing, adoption and deployment. A simple comparison is available at [speed.python.org](https://speed.python.org/comparison/?exe=12%2BL%2B3.11%2C12%2BL%2B3.12%2C12%2BL%2B3.10%2C12%2BL%2B3.9%2C12%2BL%2B3.8&ben=746&env=1&hor=false&bas=none&chart=normal+bars).
[Djangobench](https://github.com/django/djangobench/tree/master) is source of synthetic benchmarks and a useful tool for running comparisons. Below are some examples to inform your investigations.
Keep in mind while a 1.2x faster result is significant, it's only one step of the process, Celery, SQL, Redis and many other factors will influence the end result and this _python_ speed improvement will not translate 1:1 into real world performance.
### Django 4.0.10
- Djangobench 0.10.0
- Django 4.0.10
- Python 3.8.18 vs Python 3.11.5
```bash
joel@METABOX:~/djangobench/django$ djangobench --vcs=none --control=. --experiment=. --control-python=/home/joel/djangobench/py38/bin/python --experiment-python=/home/joel/djangobench/py311/bin/python -r /home/joel/djangobench/results -t 500
Running all benchmarks
Recording data to '/home/joel/djangobench/results'
Control: Django 4.0.10 (in .)
Experiment: Django 4.0.10 (in .)
Running 'multi_value_dict' benchmark ...
Min: 0.000014 -> 0.000013: 1.0304x faster
Avg: 0.000183 -> 0.000133: 1.3698x faster
Significant (t=9.325958)
Stddev: 0.00010 -> 0.00007: 1.3791x smaller (N = 500)
Running 'query_values' benchmark ...
Min: 0.000079 -> 0.000070: 1.1308x faster
Avg: 0.000084 -> 0.000074: 1.1267x faster
Significant (t=19.174361)
Stddev: 0.00001 -> 0.00001: 1.0255x larger (N = 500)
Running 'query_delete' benchmark ...
Min: 0.000082 -> 0.000074: 1.1145x faster
Avg: 0.000086 -> 0.000078: 1.0987x faster
Significant (t=17.504085)
Stddev: 0.00001 -> 0.00001: 1.1888x smaller (N = 500)
Running 'query_select_related' benchmark ...
Min: 0.016771 -> 0.013520: 1.2405x faster
Avg: 0.017897 -> 0.014149: 1.2649x faster
Significant (t=40.942990)
Stddev: 0.00190 -> 0.00077: 2.4535x smaller (N = 500)
Running 'query_aggregate' benchmark ...
Min: 0.000092 -> 0.000083: 1.1105x faster
Avg: 0.000100 -> 0.000090: 1.1107x faster
Significant (t=9.967204)
Stddev: 0.00002 -> 0.00001: 1.5003x smaller (N = 500)
Running 'query_raw_deferred' benchmark ...
Min: 0.004157 -> 0.003563: 1.1666x faster
Avg: 0.004626 -> 0.003809: 1.2143x faster
Significant (t=12.325104)
Stddev: 0.00121 -> 0.00086: 1.4047x smaller (N = 500)
Running 'query_get_or_create' benchmark ...
Min: 0.000412 -> 0.000362: 1.1385x faster
Avg: 0.000458 -> 0.000407: 1.1259x faster
Significant (t=14.169322)
Stddev: 0.00006 -> 0.00005: 1.1306x smaller (N = 500)
Running 'query_values_list' benchmark ...
Min: 0.000080 -> 0.000071: 1.1231x faster
Avg: 0.000089 -> 0.000076: 1.1706x faster
Significant (t=18.298942)
Stddev: 0.00001 -> 0.00001: 1.9398x smaller (N = 500)
Running 'url_resolve_flat_i18n_off' benchmark ...
Min: 0.055764 -> 0.045370: 1.2291x faster
Avg: 0.057670 -> 0.047020: 1.2265x faster
Significant (t=111.187780)
Stddev: 0.00206 -> 0.00059: 3.4618x smaller (N = 500)
Running 'qs_filter_chaining' benchmark ...
Min: 0.000236 -> 0.000196: 1.2034x faster
Avg: 0.000248 -> 0.000206: 1.2041x faster
Significant (t=44.893544)
Stddev: 0.00002 -> 0.00001: 1.0833x smaller (N = 500)
Running 'template_render' benchmark ...
Min: 0.000933 -> 0.000712: 1.3110x faster
Avg: 0.001003 -> 0.000777: 1.2909x faster
Significant (t=8.379095)
Stddev: 0.00043 -> 0.00042: 1.0287x smaller (N = 500)
Running 'query_get' benchmark ...
Min: 0.000259 -> 0.000230: 1.1259x faster
Avg: 0.000282 -> 0.000238: 1.1829x faster
Significant (t=42.267305)
Stddev: 0.00002 -> 0.00001: 1.7842x smaller (N = 500)
Running 'query_none' benchmark ...
Min: 0.000053 -> 0.000045: 1.1830x faster
Avg: 0.000056 -> 0.000049: 1.1449x faster
Significant (t=16.426843)
Stddev: 0.00001 -> 0.00001: 1.1267x larger (N = 500)
Running 'query_complex_filter' benchmark ...
Min: 0.000039 -> 0.000034: 1.1527x faster
Avg: 0.000041 -> 0.000037: 1.1091x faster
Significant (t=13.582718)
Stddev: 0.00000 -> 0.00001: 1.5373x larger (N = 500)
Running 'query_filter' benchmark ...
Min: 0.000127 -> 0.000112: 1.1288x faster
Avg: 0.000133 -> 0.000119: 1.1228x faster
Significant (t=22.727829)
Stddev: 0.00001 -> 0.00001: 1.1771x smaller (N = 500)
Running 'template_render_simple' benchmark ...
Min: 0.000030 -> 0.000024: 1.2405x faster
Avg: 0.000035 -> 0.000029: 1.2042x faster
Not significant
Stddev: 0.00007 -> 0.00005: 1.3190x smaller (N = 500)
Running 'default_middleware' benchmark ...
Min: -0.000047 -> -0.000054: 0.8624x faster
Avg: 0.000017 -> 0.000017: 1.0032x faster
Not significant
Stddev: 0.00037 -> 0.00037: 1.0091x larger (N = 500)
Running 'query_annotate' benchmark ...
Min: 0.000186 -> 0.000162: 1.1505x faster
Avg: 0.000207 -> 0.000178: 1.1660x faster
Significant (t=16.516089)
Stddev: 0.00003 -> 0.00003: 1.1403x smaller (N = 500)
Running 'raw_sql' benchmark ...
Min: 0.000015 -> 0.000013: 1.1070x faster
Avg: 0.000017 -> 0.000014: 1.1676x faster
Significant (t=13.598519)
Stddev: 0.00000 -> 0.00000: 2.3503x smaller (N = 500)
Running 'url_resolve_flat' benchmark ...
Min: 0.056378 -> 0.044772: 1.2592x faster
Avg: 0.058268 -> 0.046656: 1.2489x faster
Significant (t=197.176590)
Stddev: 0.00121 -> 0.00051: 2.3665x smaller (N = 500)
Running 'l10n_render' benchmark ...
Min: 0.001097 -> 0.000727: 1.5092x faster
Avg: 0.001160 -> 0.000768: 1.5101x faster
Significant (t=36.971179)
Stddev: 0.00019 -> 0.00014: 1.2946x smaller (N = 500)
Running 'query_count' benchmark ...
Min: 0.000083 -> 0.000073: 1.1302x faster
Avg: 0.000091 -> 0.000079: 1.1640x faster
Significant (t=15.049336)
Stddev: 0.00002 -> 0.00001: 1.6661x smaller (N = 500)
Running 'model_delete' benchmark ...
Min: 0.000123 -> 0.000105: 1.1701x faster
Avg: 0.000135 -> 0.000119: 1.1396x faster
Significant (t=17.781816)
Stddev: 0.00001 -> 0.00002: 1.1990x larger (N = 500)
Running 'query_iterator' benchmark ...
Min: 0.000102 -> 0.000088: 1.1605x faster
Avg: 0.000108 -> 0.000093: 1.1598x faster
Significant (t=23.872009)
Stddev: 0.00001 -> 0.00001: 1.1366x smaller (N = 500)
Running 'template_compilation' benchmark ...
Min: 0.000155 -> 0.000129: 1.2015x faster
Avg: 0.000169 -> 0.000137: 1.2317x faster
Significant (t=6.119618)
Stddev: 0.00009 -> 0.00007: 1.4162x smaller (N = 500)
Running 'query_all_multifield' benchmark ...
Min: 0.014582 -> 0.012509: 1.1658x faster
Avg: 0.015715 -> 0.013337: 1.1783x faster
Significant (t=19.183517)
Stddev: 0.00207 -> 0.00184: 1.1241x smaller (N = 500)
Running 'query_prefetch_related' benchmark ...
Min: 0.014293 -> 0.012157: 1.1758x faster
Avg: 0.015467 -> 0.013276: 1.1650x faster
Significant (t=20.607411)
Stddev: 0.00176 -> 0.00160: 1.0952x smaller (N = 500)
Running 'query_all_converters' benchmark ...
Min: 0.000536 -> 0.000464: 1.1554x faster
Avg: 0.000563 -> 0.000486: 1.1595x faster
Significant (t=38.503433)
Stddev: 0.00004 -> 0.00002: 1.6468x smaller (N = 500)
Running 'query_distinct' benchmark ...
Min: 0.000106 -> 0.000092: 1.1583x faster
Avg: 0.000127 -> 0.000096: 1.3223x faster
Significant (t=27.798102)
Stddev: 0.00002 -> 0.00001: 3.7187x smaller (N = 500)
Running 'query_dates' benchmark ...
Min: 0.000249 -> 0.000209: 1.1953x faster
Avg: 0.000275 -> 0.000228: 1.2056x faster
Significant (t=30.785168)
Stddev: 0.00003 -> 0.00002: 1.0854x smaller (N = 500)
Running 'model_save_existing' benchmark ...
Min: 0.003526 -> 0.003094: 1.1397x faster
Avg: 0.003723 -> 0.003212: 1.1591x faster
Significant (t=47.274918)
Stddev: 0.00018 -> 0.00016: 1.1817x smaller (N = 500)
Running 'query_delete_related' benchmark ...
Min: 0.000120 -> 0.000103: 1.1655x faster
Avg: 0.000132 -> 0.000111: 1.1815x faster
Significant (t=6.428771)
Stddev: 0.00005 -> 0.00004: 1.2149x smaller (N = 500)
Running 'url_reverse' benchmark ...
Min: 0.000062 -> 0.000060: 1.0318x faster
Avg: 0.000072 -> 0.000068: 1.0622x faster
Not significant
Stddev: 0.00006 -> 0.00005: 1.0531x smaller (N = 500)
Running 'query_latest' benchmark ...
Min: 0.000136 -> 0.000118: 1.1454x faster
Avg: 0.000155 -> 0.000129: 1.2008x faster
Significant (t=8.372115)
Stddev: 0.00007 -> 0.00001: 5.1365x smaller (N = 500)
Running 'form_create' benchmark ...
Min: 0.000015 -> 0.000013: 1.2319x faster
Avg: 0.000019 -> 0.000015: 1.2739x faster
Significant (t=4.158080)
Stddev: 0.00002 -> 0.00001: 1.1449x smaller (N = 500)
Running 'query_update' benchmark ...
Min: 0.000047 -> 0.000041: 1.1323x faster
Avg: 0.000052 -> 0.000044: 1.1721x faster
Significant (t=18.470635)
Stddev: 0.00001 -> 0.00000: 1.6104x smaller (N = 500)
Running 'query_in_bulk' benchmark ...
Min: 0.000152 -> 0.000136: 1.1193x faster
Avg: 0.000173 -> 0.000147: 1.1735x faster
Significant (t=16.901845)
Stddev: 0.00003 -> 0.00001: 2.1199x smaller (N = 500)
Running 'url_resolve_nested' benchmark ...
Min: 0.000043 -> 0.000034: 1.2871x faster
Avg: 0.000075 -> 0.000047: 1.6049x faster
Not significant
Stddev: 0.00066 -> 0.00023: 2.8387x smaller (N = 500)
Running 'model_creation' benchmark ...
Min: 0.000077 -> 0.000066: 1.1579x faster
Avg: 0.000088 -> 0.000072: 1.2205x faster
Significant (t=10.514202)
Stddev: 0.00003 -> 0.00001: 3.1410x smaller (N = 500)
Running 'query_order_by' benchmark ...
Min: 0.000135 -> 0.000124: 1.0945x faster
Avg: 0.000145 -> 0.000133: 1.0902x faster
Significant (t=13.574502)
Stddev: 0.00001 -> 0.00001: 1.1586x smaller (N = 500)
Running 'startup' benchmark ...
Skipped: Django 1.9 and later has changed app loading. This benchmark needs fixing anyway.
Running 'form_clean' benchmark ...
Min: 0.000005 -> 0.000003: 1.4696x faster
Avg: 0.000006 -> 0.000004: 1.4931x faster
Significant (t=11.263253)
Stddev: 0.00000 -> 0.00000: 2.2571x smaller (N = 500)
Running 'locale_from_request' benchmark ...
Min: 0.000076 -> 0.000082: 1.0895x slower
Avg: 0.000083 -> 0.000090: 1.0877x slower
Not significant
Stddev: 0.00009 -> 0.00006: 1.6230x smaller (N = 500)
Running 'query_exists' benchmark ...
Min: 0.000243 -> 0.000214: 1.1399x faster
Avg: 0.000262 -> 0.000227: 1.1571x faster
Significant (t=27.797738)
Stddev: 0.00002 -> 0.00002: 1.2601x smaller (N = 500)
Running 'query_values_10000' benchmark ...
Min: 0.005755 -> 0.005269: 1.0923x faster
Avg: 0.006184 -> 0.005587: 1.1067x faster
Significant (t=10.895954)
Stddev: 0.00094 -> 0.00079: 1.1902x smaller (N = 500)
Running 'query_exclude' benchmark ...
Min: 0.000159 -> 0.000141: 1.1256x faster
Avg: 0.000177 -> 0.000151: 1.1741x faster
Significant (t=23.556200)
Stddev: 0.00002 -> 0.00001: 1.8250x smaller (N = 500)
Running 'query_raw' benchmark ...
Min: 0.005619 -> 0.004860: 1.1562x faster
Avg: 0.006181 -> 0.005041: 1.2263x faster
Significant (t=18.008590)
Stddev: 0.00121 -> 0.00074: 1.6376x smaller (N = 500)
Running 'url_resolve' benchmark ...
Min: 0.004666 -> 0.004233: 1.1023x faster
Avg: 0.004920 -> 0.004347: 1.1318x faster
Significant (t=24.865249)
Stddev: 0.00049 -> 0.00016: 3.1507x smaller (N = 500)
Running 'model_save_new' benchmark ...
Min: 0.003420 -> 0.003105: 1.1014x faster
Avg: 0.003610 -> 0.003217: 1.1221x faster
Significant (t=42.956103)
Stddev: 0.00017 -> 0.00011: 1.6304x smaller (N = 500)
Running 'query_all' benchmark ...
Min: 0.008101 -> 0.007077: 1.1447x faster
Avg: 0.009006 -> 0.007936: 1.1348x faster
Significant (t=9.981534)
Stddev: 0.00171 -> 0.00168: 1.0215x smaller (N = 500)
```
### Django 4.2.6
- Djangobench 0.10.0
- Django 4.0.10
- Python 3.8.18 vs Python 3.11.5
```bash
joel@METABOX:~/djangobench/django$ djangobench --vcs=none --control=. --experiment=. --control-python=/home/joel/djangobench/py38/bin/python --experiment-python=/home/joel/djangobench/py311/bin/python -r /home/joel/djangobench/results -t 500
Running all benchmarks
Recording data to '/home/joel/djangobench/results'
Control: Django 4.2.6 (in .)
Experiment: Django 4.2.6 (in .)
Running 'multi_value_dict' benchmark ...
Min: -0.000004 -> 0.000013: -3.0336x slower
Avg: 0.000182 -> 0.000133: 1.3680x faster
Significant (t=9.151616)
Stddev: 0.00010 -> 0.00007: 1.3826x smaller (N = 500)
Running 'query_values' benchmark ...
Min: 0.000082 -> 0.000072: 1.1485x faster
Avg: 0.000086 -> 0.000075: 1.1462x faster
Significant (t=30.114973)
Stddev: 0.00001 -> 0.00001: 1.0258x larger (N = 500)
Running 'query_delete' benchmark ...
Min: 0.000080 -> 0.000071: 1.1169x faster
Avg: 0.000086 -> 0.000077: 1.1088x faster
Significant (t=13.459411)
Stddev: 0.00001 -> 0.00001: 1.0008x smaller (N = 500)
Running 'query_select_related' benchmark ...
Min: 0.016889 -> 0.013513: 1.2498x faster
Avg: 0.018370 -> 0.013885: 1.3230x faster
Significant (t=48.921967)
Stddev: 0.00196 -> 0.00061: 3.2174x smaller (N = 500)
Running 'query_aggregate' benchmark ...
Min: 0.000167 -> 0.000153: 1.0904x faster
Avg: 0.000182 -> 0.000165: 1.1029x faster
Significant (t=12.685517)
Stddev: 0.00002 -> 0.00002: 1.3019x smaller (N = 500)
Running 'query_raw_deferred' benchmark ...
Min: 0.004160 -> 0.003674: 1.1323x faster
Avg: 0.004596 -> 0.003888: 1.1820x faster
Significant (t=11.504156)
Stddev: 0.00117 -> 0.00073: 1.5957x smaller (N = 500)
Running 'query_get_or_create' benchmark ...
Min: 0.000421 -> 0.000356: 1.1823x faster
Avg: 0.000470 -> 0.000392: 1.2011x faster
Significant (t=14.613017)
Stddev: 0.00008 -> 0.00009: 1.0954x larger (N = 500)
Running 'query_values_list' benchmark ...
Min: 0.000080 -> 0.000070: 1.1395x faster
Avg: 0.000085 -> 0.000075: 1.1202x faster
Significant (t=20.300988)
Stddev: 0.00001 -> 0.00001: 1.0537x smaller (N = 500)
Running 'url_resolve_flat_i18n_off' benchmark ...
Min: 0.056031 -> 0.045854: 1.2219x faster
Avg: 0.057048 -> 0.048370: 1.1794x faster
Significant (t=106.668460)
Stddev: 0.00117 -> 0.00139: 1.1819x larger (N = 500)
Running 'qs_filter_chaining' benchmark ...
Min: 0.000247 -> 0.000205: 1.2080x faster
Avg: 0.000267 -> 0.000219: 1.2211x faster
Significant (t=38.507950)
Stddev: 0.00002 -> 0.00002: 1.0252x larger (N = 500)
Running 'template_render' benchmark ...
Min: 0.000956 -> 0.000761: 1.2550x faster
Avg: 0.001061 -> 0.000862: 1.2302x faster
Significant (t=6.128572)
Stddev: 0.00052 -> 0.00051: 1.0109x smaller (N = 500)
Running 'query_get' benchmark ...
Min: 0.000268 -> 0.000235: 1.1388x faster
Avg: 0.000293 -> 0.000256: 1.1411x faster
Significant (t=24.002331)
Stddev: 0.00002 -> 0.00003: 1.2917x larger (N = 500)
Running 'query_none' benchmark ...
Min: 0.000055 -> 0.000050: 1.1079x faster
Avg: 0.000061 -> 0.000055: 1.1183x faster
Significant (t=3.149707)
Stddev: 0.00003 -> 0.00004: 1.3162x larger (N = 500)
Running 'query_complex_filter' benchmark ...
Min: 0.000040 -> 0.000034: 1.1777x faster
Avg: 0.000042 -> 0.000038: 1.1267x faster
Significant (t=15.246074)
Stddev: 0.00000 -> 0.00001: 1.5250x larger (N = 500)
Running 'query_filter' benchmark ...
Min: 0.000131 -> 0.000116: 1.1288x faster
Avg: 0.000139 -> 0.000127: 1.0907x faster
Significant (t=14.448319)
Stddev: 0.00001 -> 0.00001: 1.2281x larger (N = 500)
Running 'template_render_simple' benchmark ...
Min: 0.000031 -> 0.000024: 1.2650x faster
Avg: 0.000037 -> 0.000029: 1.2895x faster
Significant (t=2.094800)
Stddev: 0.00007 -> 0.00005: 1.3630x smaller (N = 500)
Running 'default_middleware' benchmark ...
Min: -0.000037 -> -0.000060: 0.6180x faster
Avg: 0.000001 -> 0.000001: 1.0056x slower
Not significant
Stddev: 0.00002 -> 0.00002: 1.0915x smaller (N = 500)
Running 'query_annotate' benchmark ...
Min: 0.000192 -> 0.000173: 1.1122x faster
Avg: 0.000206 -> 0.000185: 1.1134x faster
Significant (t=17.849733)
Stddev: 0.00002 -> 0.00002: 1.0456x smaller (N = 500)
Running 'raw_sql' benchmark ...
Min: 0.000013 -> 0.000012: 1.0839x faster
Avg: 0.000015 -> 0.000014: 1.0882x faster
Significant (t=4.252084)
Stddev: 0.00001 -> 0.00000: 1.5868x smaller (N = 500)
Running 'url_resolve_flat' benchmark ...
Min: 0.055540 -> 0.046018: 1.2069x faster
Avg: 0.058030 -> 0.048408: 1.1988x faster
Significant (t=98.852976)
Stddev: 0.00157 -> 0.00151: 1.0444x smaller (N = 500)
Running 'l10n_render' benchmark ...
Min: 0.001604 -> 0.001253: 1.2797x faster
Avg: 0.001684 -> 0.001304: 1.2918x faster
Significant (t=37.535402)
Stddev: 0.00017 -> 0.00015: 1.1476x smaller (N = 500)
Running 'query_count' benchmark ...
Min: 0.000176 -> 0.000165: 1.0631x faster
Avg: 0.000189 -> 0.000176: 1.0755x faster
Significant (t=12.229046)
Stddev: 0.00002 -> 0.00002: 1.0395x larger (N = 500)
Running 'model_delete' benchmark ...
Min: 0.000122 -> 0.000104: 1.1743x faster
Avg: 0.000152 -> 0.000115: 1.3227x faster
Significant (t=19.812953)
Stddev: 0.00004 -> 0.00001: 2.6554x smaller (N = 500)
Running 'query_iterator' benchmark ...
Min: 0.000108 -> 0.000094: 1.1518x faster
Avg: 0.000119 -> 0.000098: 1.2203x faster
Significant (t=21.984884)
Stddev: 0.00002 -> 0.00001: 2.7750x smaller (N = 500)
Running 'template_compilation' benchmark ...
Min: 0.000164 -> 0.000148: 1.1034x faster
Avg: 0.000184 -> 0.000162: 1.1386x faster
Significant (t=4.665298)
Stddev: 0.00008 -> 0.00007: 1.2952x smaller (N = 500)
Running 'query_all_multifield' benchmark ...
Min: 0.014802 -> 0.012188: 1.2144x faster
Avg: 0.016029 -> 0.013294: 1.2057x faster
Significant (t=21.516971)
Stddev: 0.00210 -> 0.00191: 1.0984x smaller (N = 500)
Running 'query_prefetch_related' benchmark ...
Min: 0.013401 -> 0.011583: 1.1569x faster
Avg: 0.014822 -> 0.013366: 1.1090x faster
Significant (t=11.422100)
Stddev: 0.00170 -> 0.00229: 1.3410x larger (N = 500)
Running 'query_all_converters' benchmark ...
Min: 0.000499 -> 0.000429: 1.1618x faster
Avg: 0.000531 -> 0.000455: 1.1670x faster
Significant (t=42.716720)
Stddev: 0.00002 -> 0.00003: 1.5394x larger (N = 500)
Running 'query_distinct' benchmark ...
Min: 0.000108 -> 0.000095: 1.1397x faster
Avg: 0.000116 -> 0.000100: 1.1646x faster
Significant (t=25.915629)
Stddev: 0.00001 -> 0.00001: 1.1204x larger (N = 500)
Running 'query_dates' benchmark ...
Min: 0.000333 -> 0.000290: 1.1490x faster
Avg: 0.000365 -> 0.000326: 1.1207x faster
Significant (t=18.213858)
Stddev: 0.00003 -> 0.00003: 1.0118x larger (N = 500)
Running 'model_save_existing' benchmark ...
Min: 0.003455 -> 0.003081: 1.1215x faster
Avg: 0.003764 -> 0.003326: 1.1316x faster
Significant (t=32.229651)
Stddev: 0.00023 -> 0.00020: 1.1398x smaller (N = 500)
Running 'query_delete_related' benchmark ...
Min: 0.000122 -> 0.000102: 1.1946x faster
Avg: 0.000131 -> 0.000113: 1.1564x faster
Significant (t=5.027485)
Stddev: 0.00005 -> 0.00006: 1.4129x larger (N = 500)
Running 'url_reverse' benchmark ...
Min: 0.000068 -> 0.000067: 1.0193x faster
Avg: 0.000075 -> 0.000074: 1.0157x faster
Not significant
Stddev: 0.00006 -> 0.00005: 1.1543x smaller (N = 500)
Running 'query_latest' benchmark ...
Min: 0.000147 -> 0.000138: 1.0631x faster
Avg: 0.000167 -> 0.000148: 1.1277x faster
Significant (t=11.353029)
Stddev: 0.00003 -> 0.00002: 1.6091x smaller (N = 500)
Running 'form_create' benchmark ...
Min: 0.000016 -> 0.000013: 1.2659x faster
Avg: 0.000020 -> 0.000015: 1.2770x faster
Significant (t=3.482649)
Stddev: 0.00002 -> 0.00002: 1.0947x larger (N = 500)
Running 'query_update' benchmark ...
Min: 0.000047 -> 0.000043: 1.0971x faster
Avg: 0.000050 -> 0.000046: 1.0691x faster
Significant (t=9.363513)
Stddev: 0.00001 -> 0.00000: 1.2636x smaller (N = 500)
Running 'query_in_bulk' benchmark ...
Min: 0.000157 -> 0.000143: 1.0970x faster
Avg: 0.000178 -> 0.000162: 1.0981x faster
Significant (t=9.031182)
Stddev: 0.00002 -> 0.00003: 1.5173x larger (N = 500)
Running 'url_resolve_nested' benchmark ...
Min: 0.000046 -> 0.000038: 1.2179x faster
Avg: 0.000075 -> 0.000052: 1.4505x faster
Not significant
Stddev: 0.00059 -> 0.00024: 2.4300x smaller (N = 500)
Running 'model_creation' benchmark ...
Min: 0.000071 -> 0.000065: 1.1058x faster
Avg: 0.000079 -> 0.000073: 1.0876x faster
Significant (t=2.786580)
Stddev: 0.00003 -> 0.00004: 1.1518x larger (N = 500)
Running 'query_order_by' benchmark ...
Min: 0.000146 -> 0.000128: 1.1407x faster
Avg: 0.000154 -> 0.000138: 1.1206x faster
Significant (t=14.021341)
Stddev: 0.00002 -> 0.00002: 1.2540x larger (N = 500)
Running 'startup' benchmark ...
Skipped: Django 1.9 and later has changed app loading. This benchmark needs fixing anyway.
Running 'form_clean' benchmark ...
Min: 0.000005 -> 0.000004: 1.4613x faster
Avg: 0.000006 -> 0.000004: 1.3654x faster
Significant (t=12.763128)
Stddev: 0.00000 -> 0.00000: 1.1666x larger (N = 500)
Running 'locale_from_request' benchmark ...
Min: 0.000097 -> 0.000108: 1.1090x slower
Avg: 0.000108 -> 0.000120: 1.1178x slower
Significant (t=-3.057677)
Stddev: 0.00007 -> 0.00006: 1.1186x smaller (N = 500)
Running 'query_exists' benchmark ...
Min: 0.000273 -> 0.000234: 1.1698x faster
Avg: 0.000290 -> 0.000248: 1.1686x faster
Significant (t=39.518859)
Stddev: 0.00002 -> 0.00002: 1.2025x smaller (N = 500)
Running 'query_values_10000' benchmark ...
Min: 0.005601 -> 0.005298: 1.0571x faster
Avg: 0.006023 -> 0.005691: 1.0583x faster
Significant (t=6.167352)
Stddev: 0.00082 -> 0.00088: 1.0752x larger (N = 500)
Running 'query_exclude' benchmark ...
Min: 0.000159 -> 0.000140: 1.1367x faster
Avg: 0.000165 -> 0.000149: 1.1020x faster
Significant (t=19.643154)
Stddev: 0.00001 -> 0.00001: 1.2636x larger (N = 500)
Running 'query_raw' benchmark ...
Min: 0.005764 -> 0.004630: 1.2450x faster
Avg: 0.006169 -> 0.004881: 1.2638x faster
Significant (t=20.996453)
Stddev: 0.00109 -> 0.00083: 1.3105x smaller (N = 500)
Running 'url_resolve' benchmark ...
Min: 0.004928 -> 0.004597: 1.0721x faster
Avg: 0.005217 -> 0.004716: 1.1063x faster
Significant (t=46.893945)
Stddev: 0.00022 -> 0.00010: 2.2192x smaller (N = 500)
Running 'model_save_new' benchmark ...
Min: 0.003404 -> 0.003012: 1.1301x faster
Avg: 0.003494 -> 0.003105: 1.1251x faster
Significant (t=45.888484)
Stddev: 0.00014 -> 0.00013: 1.0298x smaller (N = 500)
Running 'query_all' benchmark ...
Min: 0.007971 -> 0.007085: 1.1250x faster
Avg: 0.009091 -> 0.008147: 1.1159x faster
Significant (t=7.583074)
Stddev: 0.00183 -> 0.00210: 1.1518x larger (N = 500)
```

View File

@ -0,0 +1,203 @@
# SQL
SQL Tuning is usually the realm of experienced Database Admins, as it can be full of missteps leading to worse performance. It is _extremely_ important that you take it slowly, make one change at a time with dedicated research and test before and after.
Before you start down this path its best to update [MariaDB](https://mariadb.org/download/?t=repo-config) / MySQL. Performance Schemas, some default tuning and other general performance improvements are only available on new versions. You must also allow your server to run for 24 hours at least to gather accurate data.
## MySQLTuner
[MySQLTuner](https://github.com/major/MySQLTuner-perl) is a Perl script that will analyze inbuilt metrics and spit out recommendations.
### [performance_schema](https://mariadb.com/kb/en/performance-schema-system-variables/#performance_schema)
This should be ON for 24 hours before applying any recommendations, then can be turned _OFF_ to save Memory while its not needed.
```bash
-------- Performance schema ------------------------------------------------------------------------
[--] Performance_schema is activated.
[--] Memory used by Performance_schema: 105.7M
[--] Sys schema is installed.
# 105M could be significant depending on your hardware
```
## SQL Variables
### [skip-name-resolve](https://mariadb.com/kb/en/server-system-variables/#skip_name_resolve)
While on, SQL will perform a dns resolve for all connections, if your database is connected via IP, this will save you a handful of cpu cycles per connection.
Note you must use 127.0.0.1 for localhost connections, and all entries in GRANT tables (permissions), must use IP addresses.
### [table_definition_cache](https://mariadb.com/kb/en/server-system-variables/#table_definition_cache)
Will usually need to be expanded on installs with many extensions
Most installs should cache all their tables, but if your hit rate is still quite high, you may have a lot of rarely used tables that you don't need to waste memory caching.
```bash
[OK] Table cache hit rate: 63% (2K hits / 4K requests).
# Only 63% of our queries are using this cache
table_definition_cache (400) > 567 or -1 (autosizing if supported)
# Here We have 567 tables, but a default cache of only 400.
```
```bash
[OK] Table cache hit rate: 99% (372M hits / 372M requests)
[OK] table_definition_cache (600) is greater than number of tables (567)
# Much better
```
### [innodb_buffer_pool_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_buffer_pool_size)
This is in short, the amount of memory assigned to store data for faster reads. If you are memory starved you should not increase this variable regardless of the suggestions of this tool. Pushing SQL cache to pagefile will not result in faster queries.
If you are not memory starved, you can wind this up to the amount of total data you have to store it all in memory. This would be a significant performance increase for larger installs on dedicated hardware with memory to spare.
```bash
[!!] InnoDB buffer pool / data size: 128.0M / 651.6M
# I have 651mb of _possible_ data to cache.
# We won't and shouldn't cache it all unless we have excess memory to spare.
...
[!!] InnoDB Read buffer efficiency: 0% (-2019 hits / 0 total)
# A low ratio here would suggest more Memory can be used effectively.
# A high ratio might mean we have most of our regularly used data cached already
```
### [innodb_log_buffer_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_buffer_size) / [innodb_log_file_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_file_size)
[innodb_log_file_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_file_size) This is your _write_ log, used to redo any commits in the event of a crash. MySQLTuner recommends this be 1/4 of your innodb_buffer_pool / read buffer. I would not lower this past the default size.
[innodb_log_buffer_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_buffer_size) This is the memory buffer for the write log. Larger transactions will benefit from a larger setting.
```bash
[!!] Ratio InnoDB log file size / InnoDB Buffer pool size (75%): 96.0M \* 1 / 128.0M should be equal to 25%
# Here our write log file is 75% of our read buffer, but 96MB is the default so we probably wont shrink it further
...
[OK] InnoDB Write Log efficiency: 99.11% (23167614 hits / 23375465 total) # Our transactions are typically not large enough to exhaust the write log buffer,
[OK] InnoDB log waits: 0.00% (0 waits / 207851 writes)
```
### [innodb_file_per_table](https://mariadb.com/kb/en/innodb-system-variables/#innodb_file_per_table)
This is not for performance, but for file system utilization and ease of use. While off all tables are stored in a single monolith file, as opposed to individual files. This is deprecated and set to ON in MariaDB 11.x
```bash
[OK] InnoDB File per table is activated
```
### [join_buffer_size](https://mariadb.com/kb/en/server-system-variables/#join_buffer_size)
It is always better to optimize a table with indexes, if you have valuable performance data and analysis please reach out to either the Alliance Auth or Community dev responsible for the data that could benefit from indexes. MySQLTuner will likely recommend increasing this number for as long as there are any queries that could benefit, regardless of their resulting performance impact.
Also keep in mind this is _per thread_, if you have a potential 200 connections, 256KB * 200 = 50MB, scaling this setting out too far can result in more memory use than expected.
```bash
[!!] Joins performed without indexes: 67646
```
```bash
[OK] No joins without indexes
# An ideal scenario. With well designed apps this is possible with a default join buffer.
```
### [tmp_table_size](https://mariadb.com/kb/en/server-system-variables/#tmp_table_size) / [max_heap_table_size](https://mariadb.com/kb/en/server-system-variables/#max_heap_table_size)
If a temporary table must be created due to a lack of other optimizations or large queries, it may only be stored in memory under this size. Any larger and it is performed on disk reducing performance.
tmp_table_size and max_heap_table_size should be increased together.
```bash
[!!] Temporary tables created on disk: 32% (775 on disk / 2K total)
# 32% of my temp tables are performed on disk. If you increase this size, monitor if your performance improves.
# If it does not you may have data of a certain size that is impractical to cache, and you can reclaim this memory.
```
```bash
[OK] Temporary tables created on disk: 0% (5K on disk / 4M total)
# Here only a miniscule amount of my temp tables are done on disk. No action required
```
### key_buffer_size
Index buffer for MyISAM tables, If you use no or very little data in MyISAM tables. You may reclaim some memory here
In this example we still have some MyISAM tables, you may have none
```bash
[--] General MyIsam metrics:
[--] +-- Total MyISAM Tables : 67
[--] +-- Total MyISAM indexes : 7.1M
[--] +-- KB Size :8.0M
[--] +-- KB Used Size :1.5M
[--] +-- KB used :18.3%
[--] +-- Read KB hit rate: 0% (0 cached / 0 reads)
[--] +-- Write KB hit rate: 0% (0 cached / 0 writes)
[!!] Key buffer used: 18.3% (1.5M used / 8.0M cache) # We have only filled 1.5M of the 8 assigned
[OK] Key buffer size / total MyISAM indexes: 8.0M/7.1M # This is the max theoretical buffer to cache all my indexes
Variables to adjust:
key_buffer_size (~ 1M)
# Tuner has seen that we barely use this buffer and it can be shrunk, if you care about its impact don't lower this below your total indexes.
```
### [aria_pagecache_buffer_size](https://mariadb.com/kb/en/aria-system-variables/#aria_pagecache_buffer_size)
Index and data buffer for Aria tables, If you use no or very little data in Aria tables. You may reclaim some memory here
```bash
-------- Aria Metrics ------------------------------------------------------------------------------
[--] Aria Storage Engine is enabled.
[OK] Aria pagecache size / total Aria indexes: 128.0M/328.0K # i use a fraction of my aria buffer since i have no aria tables.
[OK] Aria pagecache hit rate: 99.9% (112K cached / 75 reads) # Aria is used internally for MariaDB, so you still want an incredibly high ratio here.
```
## Swappiness
Swappiness is not an SQL variable but part of your system kernel. Swappiness controls how much free memory a server "likes" to have at any given time, and how frequently it shifts data to swapfile in order to free up memory. Desktop operating systems will have this value set quite high, whereas servers are less aggressive with their swapfile.
Database workloads especially benefit from having their caches stay in memory and will recommend values under 10 for a dedicated database server. 10 is a good compromise for a mixed use server with adequate memory.
If your server is memory starved, leave swapfile aggressive to ensure it is moving memory around as needed.
```bash
joel@METABOX:~/aa_dev$ free -m
total used free shared buff/cache available
Mem: 15998 1903 13372 2 722 13767
Swap: 4096 1404 2691
# Here we can see a lot of memory page (1404MB) sitting in swap while there is free memory (13372MB) available
```
```bash
[root@auth ~]# free -m
total used free shared buff/cache available
Mem: 738 611 59 1 68 35
Swap: 2047 1014 1033
# Here we can see a memory starved server highly utilizing swap already. I wouldn't mess with it too much. (vm.swappiness is 30)
```
```bash
[root@mysql ~]# free -m
total used free shared buff/cache available
Mem: 738 498 95 7 145 120
Swap: 2047 289 1758
# Here we can see a dedicated single use Database Server, Swappiness is 10 here because we have been careful not to starve it of memory and there is low potential to impact other applications
```
```bash
[--] Information about kernel tuning:
...
[--] vm.swappiness = 30
[xx] Swappiness is < 10.
...
vm.swappiness <= 10 (echo 10 > /proc/sys/vm/swappiness) or vm.swappiness=10 in /etc/sysctl.conf
```
## Max Asynchronous IO
Unless you are still operating on spinning rust (Hard Disk Drives), or an IO limited VPS, you can likely increase this value. Database workloads appreciate the additional scaling.
```bash
[--] Information about kernel tuning:
[--] fs.aio-max-nr = 65536
...
fs.aio-max-nr > 1M (echo 1048576 > /proc/sys/fs/aio-max-nr) or fs.aio-max-nr=1048576 in /etc/sysctl.conf
```