{"id":19816109,"url":"https://github.com/nofeaturesonlybugs/sqlhbenchmarks","last_synced_at":"2025-11-07T09:02:37.621Z","repository":{"id":140050024,"uuid":"372638258","full_name":"nofeaturesonlybugs/sqlhbenchmarks","owner":"nofeaturesonlybugs","description":"Benchmarking package for my sqlh package.","archived":false,"fork":false,"pushed_at":"2022-05-14T17:23:07.000Z","size":104,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-30T02:02:37.586Z","etag":null,"topics":["go","go-database","go-sql","go-sqlh","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nofeaturesonlybugs.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.txt","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-31T22:02:50.000Z","updated_at":"2023-09-14T19:24:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"9848a478-2f52-4072-b722-21d653c4761d","html_url":"https://github.com/nofeaturesonlybugs/sqlhbenchmarks","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nofeaturesonlybugs/sqlhbenchmarks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nofeaturesonlybugs%2Fsqlhbenchmarks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nofeaturesonlybugs%2Fsqlhbenchmarks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nofeaturesonlybugs%2Fsqlhbenchmarks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nofeaturesonlybugs%2Fsqlhbenchmarks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nofeaturesonlybugs","download_url":"https://codeload.github.com/nofeaturesonlybugs/sqlhbenchmarks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nofeaturesonlybugs%2Fsqlhbenchmarks/sbom","scorecard":{"id":693039,"data":{"date":"2025-08-11","repo":{"name":"github.com/nofeaturesonlybugs/sqlhbenchmarks","commit":"bd732eeb2dd945a3f956e52def4275fe31879104"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/13 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T02:47:34.703Z","repository_id":140050024,"created_at":"2025-08-22T02:47:34.703Z","updated_at":"2025-08-22T02:47:34.703Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":283159045,"owners_count":26788985,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-07T02:00:06.343Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","go-database","go-sql","go-sqlh","golang"],"created_at":"2024-11-12T10:08:24.824Z","updated_at":"2025-11-07T09:02:37.603Z","avatar_url":"https://github.com/nofeaturesonlybugs.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"`sqlhbenchmarks` is a sibling benchmarking package for `github.com/nofeaturesonlybugs/sqlh`.  I decided to break the benchmarks out of `sqlh` because:  \n\n* The benchmark code is rather verbose and greatly increases the code base for `sqlh`.\n* Keeping the benchmark code in `sqlh` increases the number of dependencies in `sqlh` even though it's not using them for anything practical.\n\nMy primary goals with my benchmark testing were to evaluate:\n\n1. Is `sqlh` comparable in performance to currently accepted and widely used packages?\n2. What are the weak areas where I can come back later for optimizations?\n3. What is the **true** cost of `reflect` when pointed at a real database when other factors start to matter (network IO, disk IO at the database server)?\n4. To act as something of a stress test by working with record sets of various sizes.\n\nI'll summarize my results with the following:\n1. I think `sqlh.Scanner` is roughly on par with existing packages and APIs; thus I feel confident using it in my applications anywhere I'd have considered using `sqlx` or `sqlscan`.\n2. `model.Models` is probably sufficient for small to medium applications but is lacking in a few benchmarks (not to mention the somewhat limited current feature set).  I plan to use it in my small to medium sized applications if that's worth anything to you.\n3. Once you factor in a real database the cost of `reflect` starts to dwindle.\n\n## Repeating These Tests  \nIf you have any desire to repeat these benchmarks for your environment or as part of evaluating which SQL package to use in Go:  \n\n* Create a `TEST_POSTGRES` environment variable with a correct DSN for `lib/pq` to run the Postgres tests.  The user in the DSN will need to be able to perform some `ALTER TABLE` statements; see `schema.go` for the exact statements.\n* Create a `TEST_SQLITE` environment variable with a correct DSN for Sqlite.  Out of the box this package uses `modernc.org/sqlite`; you can make slight alterations to `functions_sqlite.go` to point it at `mattn` instead.\n\n## Notes on Sqlite  \nMy `model.Models` type only supports grammars with a `RETURNING` clause; therefore to benchmark Sqlite I needed to use version 3.35.  Originally I was using the `github.com/mattn` package (and a specific commit for Sqlite 3.35) but was having trouble when switching back and forth between Windows and Debian for benchmarks.  Eventually I substituted `github.com/mattn`'s Sqlite for `modernc.org/sqlite`.  This satisfied my desire of having something other than Postgres to benchmark against however I do not use Sqlite professionally; I don't know if the `modernc` version of Sqlite is production ready (seems to be experimental).  Even though I do not present them here I will say the `mattn` Sqlite benchmarks were more performant when I did have it working.\n\n## Notes on `gorm`  \nSince `gorm` was relatively easy to point at Postgres I included it in the `lib/pq` driver benchmarks.  I did not feel like struggling to get `gorm` to behave with `modernc` Sqlite or `sqlmock` so it is not present in those benchmarks.\n\n`gorm` has very good performance when inserting or updating slices of records.  Obviously it is using some type of bulk operation internally when asked to work with slices of records.  In such benchmarks where I've included `gorm` it is not really a fair comparison -- the other libraries could probably achieve similar results if written to do so.  However this improved performance with `gorm` \"just worked\" and required no extra effort on my part.  I felt that was noteworthy and included it in such benchmarks even if the comparison is unfair.  Kudos to the `gorm` team in this regard.\n\n## Notes on `squirrel`  \n`squirrel` was an interesting experience.  I'd had no experience with the package prior to including it in my benchmarks.  I do find it to be an improvement in placing query arguments next to where they're used in the query, especially when creating `UPDATE` statements.  I'm not overly fond of the introduction of new types to handle things like prepared statements although I understand the reasoning.  `squirrel` is generally more memory hungry than other packages.\n\nFurther - since this is my first time using `squirrel` - it's possible I may have made mistakes in setting it up for prepared statements in the relevant benchmarks.  If anyone happens to check my work and finds errors please let me know and I will update the benchmarks.\n\n## Hardware\n```\ngoos: windows\ngoarch: amd64\npkg: github.com/nofeaturesonlybugs/sqlh/benchmarks\ncpu: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz\n```\n\n## Scanning with `sqlmock`  \nThe following tests:  \n\n* Use `sqlmock` for setting up a mock database.\n* Perform `SELECT * FROM table LIMIT %v` where the limits are: 5, 50, 100, 500, 1000, \u0026 10000\n* And scan into the following struct:\n```go\ntype SaleReport struct {\n\tId                 int    `json:\"id\" db:\"pk\"`\n\tCreatedTime        string `json:\"created_time\" db:\"created_tmz\"`\n\tModifiedTime       string `json:\"modified_time\" db:\"modified_tmz\"`\n\tPrice              int    `json:\"price\" db:\"price\"`\n\tQuantity           int    `json:\"quantity\" db:\"quantity\"`\n\tTotal              int    `json:\"total\" db:\"total\"`\n\tCustomerId         int    `json:\"customer_id\" db:\"customer_id\"`\n\tCustomerFirst      string `json:\"customer_first\" db:\"customer_first\"`\n\tCustomerLast       string `json:\"customer_last\" db:\"customer_last\"`\n\tVendorId           int    `json:\"vendor_id\" db:\"vendor_id\"`\n\tVendorName         string `json:\"vendor_name\" db:\"vendor_name\"`\n\tVendorDescription  string `json:\"vendor_description\" db:\"vendor_description\"`\n\tVendorContactId    int    `json:\"vendor_contact_id\" db:\"vendor_contact_id\"`\n\tVendorContactFirst string `json:\"vendor_contact_first\" db:\"vendor_contact_first\"`\n\tVendorContactLast  string `json:\"vendor_contact_last\" db:\"vendor_contact_last\"`\n}\n```\nMy interpretation of the results:  \n* Without a real database the cost of `reflect` is more pronounced for small record selections.\n* Objectively `sqlh.Scanner` is the *worst* performing although not by much.  There's three reasons this may be the case:  \n  * `set` and therefore `sqlh` does not use `FieldByName` methods in `reflect` due to a bug in the `reflect` package.\n  * `set` instantiates deeply nested structs if they are pointers and `nil`\n  * `set`'s struct traversal when requesting fields by mapped names *could* be improved; I have some thoughts on how but nothing concrete as of yet.\n```bash\n# records\ndatabase/sql_5_rows-8              10000\t    103287 ns/op\t    2917 B/op\t      36 allocs/op\nsqlx_5_rows-8                       5990\t    247959 ns/op\t    3607 B/op\t      39 allocs/op\nscany_5_rows-8                      4126\t    327388 ns/op\t    3086 B/op\t      40 allocs/op\nsqlh_5_rows-8                       3156\t    403795 ns/op\t    3832 B/op\t      43 allocs/op\n# 50 records\ndatabase/sql_50_rows-8         \t    2790\t    459121 ns/op\t    2902 B/op\t      36 allocs/op\nsqlx_50_rows-8                 \t    2626\t    495046 ns/op\t    3623 B/op\t      39 allocs/op\nscany_50_rows-8               \t    2392\t    543458 ns/op\t    3128 B/op\t      40 allocs/op\nsqlh_50_rows-8                 \t    2046\t    604777 ns/op\t    3864 B/op\t      43 allocs/op\n# 100 records\ndatabase/sql_100_rows-8             1966\t    697026 ns/op\t    2920 B/op\t      36 allocs/op\nsqlx_100_rows-8                \t    1551\t    766337 ns/op\t    3663 B/op\t      39 allocs/op\nscany_100_rows-8               \t    1596\t    732904 ns/op\t    3118 B/op\t      40 allocs/op\nsqlh_100_rows-8                \t    1444\t    761937 ns/op\t    3911 B/op\t      43 allocs/op\n# 500 records\ndatabase/sql_500_rows-8        \t    1528\t    819504 ns/op\t    3008 B/op\t      36 allocs/op\nsqlx_500_rows-8                \t    1519\t    889164 ns/op\t    3677 B/op\t      39 allocs/op\nscany_500_rows-8               \t    1333\t   1041175 ns/op\t    3247 B/op\t      41 allocs/op\nsqlh_500_rows-8                     1345\t    996992 ns/op\t    4036 B/op\t      44 allocs/op\n# 1,000 records\ndatabase/sql_1000_rows-8            1388\t    944315 ns/op\t    3037 B/op\t      36 allocs/op\nsqlx_1000_rows-8                    1232\t    966885 ns/op\t    3795 B/op\t      40 allocs/op\nscany_1000_rows-8                   1230\t    975264 ns/op\t    3457 B/op\t      42 allocs/op\nsqlh_1000_rows-8                    1134\t    998770 ns/op\t    4259 B/op\t      46 allocs/op\n# 10,000 records\ndatabase/sql_10000_rows-8           1081\t   1174419 ns/op\t    4684 B/op\t      45 allocs/op\nsqlx_10000_rows-8                    970\t   1169252 ns/op\t    6331 B/op\t      60 allocs/op\nscany_10000_rows-8                  1065\t   1131304 ns/op\t    7770 B/op\t      68 allocs/op\nsqlh_10000_rows-8                   1003\t   1190989 ns/op\t    8940 B/op\t      83 allocs/op\n```\n\n## Scanning Postgres using `lib/pq` driver:  \nThe following tests:  \n\n* Are pointed at a local network instance of Postgres.\n* Perform `SELECT * FROM table LIMIT %v` where the limits are: 5, 50, 100, 500, \u0026 1000\n* And scan into the following struct:\n```go\ntype Address struct {\n\tId           int    `json:\"id\" db:\"pk\" model:\"key,auto\" gorm:\"column:pk;primaryKey\"`\n\tCreatedTime  Time   `json:\"created_time\" db:\"created_tmz\" model:\"inserted\" gorm:\"-\"`\n\tModifiedTime Time   `json:\"modified_time\" db:\"modified_tmz\" model:\"inserted,updated\" gorm:\"-\"`\n\tStreet       string `json:\"street\"`\n\tCity         string `json:\"city\"`\n\tState        string `json:\"state\"`\n\tZip          string `json:\"zip\"`\n\t//\n\tpushModified Time\n}\n```\n\nThese results are a little more difficult to draw conclusions from.  We're at the mercy of network IO and load on the database, which should have been fairly consistent throughout the benchmarks.  We're also at the mercy of how Postgres stores records in memory and decides to use them for consecuitive similar requests; in other words running\na `SELECT` statement could easily affect the performance of the next one.\n\nI ran all of my benchmarks multiple times and in any result below where one is doing particularly bad (or good) I very likely had a result where it landed on the other end of the spectrum.\n\nIn general I conclude that all of them perform roughly on par with each other in my simple benchmark.  Certainly there are cases where one package is conclusively better than another but that is beyond the scope of my goals.\n```bash\n# 5 records\ndatabase/sql_5_rows-8         \t    6807\t    211957 ns/op\t    2753 B/op\t      84 allocs/op\nGORM_5_rows-8                 \t    6654\t    234121 ns/op\t    7934 B/op\t     201 allocs/op\nsqlx_5_rows-8                 \t    7126\t    195034 ns/op\t    3448 B/op\t      92 allocs/op\nscany_5_rows-8                \t    6697\t    179223 ns/op\t    5333 B/op\t     188 allocs/op\nsqlh_5_rows-8                 \t    6957\t    187767 ns/op\t    4406 B/op\t     104 allocs/op\n# 50 records\ndatabase/sql_50_rows-8        \t    3846\t    281356 ns/op\t   19434 B/op\t     710 allocs/op\nGORM_50_rows-8                \t    3645\t    389633 ns/op\t   36408 B/op\t    1418 allocs/op\nsqlx_50_rows-8                \t    2569\t    439411 ns/op\t   23174 B/op\t     763 allocs/op\nscany_50_rows-8               \t    2108\t    486062 ns/op\t   28727 B/op\t     904 allocs/op\nsqlh_50_rows-8                \t    2108\t    490222 ns/op\t   29477 B/op\t     865 allocs/op\n# 100 records\ndatabase/sql_100_rows-8       \t    2242\t    455634 ns/op\t   37986 B/op\t    1412 allocs/op\nGORM_100_rows-8               \t    2048\t    592872 ns/op\t   68158 B/op\t    2773 allocs/op\nsqlx_100_rows-8               \t    2461\t    529780 ns/op\t   45153 B/op\t    1515 allocs/op\nscany_100_rows-8              \t    2382\t    563152 ns/op\t   54625 B/op\t    1706 allocs/op\nsqlh_100_rows-8               \t    2518\t    491763 ns/op\t   57407 B/op\t    1717 allocs/op\n# 500 records\ndatabase/sql_500_rows-8       \t    1041\t   1302823 ns/op\t  191128 B/op\t    7669 allocs/op\nGORM_500_rows-8               \t     534\t   2023785 ns/op\t  325790 B/op\t   14227 allocs/op\nsqlx_500_rows-8               \t     918\t   1264888 ns/op\t  226455 B/op\t    8168 allocs/op\nscany_500_rows-8              \t     750\t   1783926 ns/op\t  266028 B/op\t    8758 allocs/op\nsqlh_500_rows-8               \t     840\t   1644985 ns/op\t  283867 B/op\t    9168 allocs/op\n# 1,000 records\ndatabase/sql_1000_rows-8      \t     440\t   2557591 ns/op\t  385111 B/op\t   15681 allocs/op\nGORM_1000_rows-8              \t     315\t   3682919 ns/op\t  650095 B/op\t   28736 allocs/op\nsqlx_1000_rows-8              \t     243\t   5090719 ns/op\t  454025 B/op\t   16677 allocs/op\nscany_1000_rows-8             \t     187\t   5714156 ns/op\t  534367 B/op\t   17776 allocs/op\nsqlh_1000_rows-8              \t     222\t   5068332 ns/op\t  578752 B/op\t   18684 allocs/op\n```\n\n## Scanning Sqlite using `modernc.org/sqlite` (Sqlite 3.35) driver:  \nThis benchmark was performed with the same `SELECT` and scan destination as the Postgres `SELECT` benchmark.\n\n```bash\n# 5 records\ndatabase/sql_5_rows-8          12458\t     96676 ns/op\t    7320 B/op\t     250 allocs/op\nsqlx_5_rows-8                  10000\t    101621 ns/op\t    8038 B/op\t     258 allocs/op\nscany_5_rows-8                 10000\t    112007 ns/op\t    9834 B/op\t     354 allocs/op\nsqlh_5_rows-8                  10000\t    103653 ns/op\t    8990 B/op\t     270 allocs/op\n# 50 records\ndatabase/sql_50_rows-8          3724\t    305367 ns/op\t   67448 B/op\t    2275 allocs/op\nsqlx_50_rows-8                  3951\t    326165 ns/op\t   71224 B/op\t    2328 allocs/op\nscany_50_rows-8                 3415\t    347603 ns/op\t   76601 B/op\t    2469 allocs/op\nsqlh_50_rows-8                  3453\t    350259 ns/op\t   77392 B/op\t    2430 allocs/op\n# 100 records\ndatabase/sql_100_rows-8         2318\t    532861 ns/op\t  134089 B/op\t    4526 allocs/op\nsqlx_100_rows-8                 2119\t    564847 ns/op\t  140973 B/op\t    4629 allocs/op\nscany_100_rows-8                2013\t    603275 ns/op\t  150671 B/op\t    4820 allocs/op\nsqlh_100_rows-8                 1963\t    603979 ns/op\t  153653 B/op\t    4831 allocs/op\n# 500 records\ndatabase/sql_500_rows-8          501\t   2428738 ns/op\t  673477 B/op\t   23171 allocs/op\nsqlx_500_rows-8                  456\t   2662145 ns/op\t  709732 B/op\t   23674 allocs/op\nscany_500_rows-8                 438\t   2707386 ns/op\t  746132 B/op\t   24265 allocs/op\nsqlh_500_rows-8                  435\t   2776479 ns/op\t  771244 B/op\t   24676 allocs/op\n# 1,000 records\ndatabase/sql_1000_rows-8         253\t   4725117 ns/op\t 1351002 B/op\t   46671 allocs/op\nsqlx_1000_rows-8                 228\t   4974677 ns/op\t 1423145 B/op\t   47674 allocs/op\nscany_1000_rows-8                224\t   5307015 ns/op\t 1494309 B/op\t   48766 allocs/op\nsqlh_1000_rows-8                 222\t   5395924 ns/op\t 1544802 B/op\t   49676 allocs/op\n```\n\n## Postgres - Dumb Insert  \nThe following benchmarks show iterating a set of `X` records and inserting them without any database transactions or prepared statements.  Certainly you want to avoid this in your application if possible but there are times where it's what your application will need to do.\n\nResults are fairly consistent across the board.  \n```bash\n# 5 records\ndatabase/sql_insert_5_row(s)-8         \t     220\t   5045438 ns/op\t    6789 B/op\t     180 allocs/op\nGORM_insert_5_row(s)-8                 \t     208\t   6058386 ns/op\t   33622 B/op\t     471 allocs/op\nsquirrel_insert_5_row(s)-8             \t     216\t   5424851 ns/op\t   28262 B/op\t     665 allocs/op\nsqlh/model_insert_5_row(s)-8         \t     225\t   6118051 ns/op\t    8701 B/op\t     205 allocs/op\n# 50 records\ndatabase/sql_insert_50_row(s)-8        \t      22\t  57294218 ns/op\t   67819 B/op\t    1800 allocs/op\nGORM_insert_50_row(s)-8                \t      20\t  62065835 ns/op\t  334900 B/op\t    4710 allocs/op\nsquirrel_insert_50_row(s)-8            \t      18\t  56739317 ns/op\t  282610 B/op\t    6653 allocs/op\nsqlh/model_insert_50_row(s)-8        \t      21\t  60169900 ns/op\t   86988 B/op\t    2051 allocs/op\n# 100 records\ndatabase/sql_insert_100_row(s)-8       \t      10\t 117970890 ns/op\t  135688 B/op\t    3602 allocs/op\nGORM_insert_100_row(s)-8               \t       9\t 126497011 ns/op\t  671555 B/op\t    9427 allocs/op\nsquirrel_insert_100_row(s)-8           \t      10\t 118073370 ns/op\t  564725 B/op\t   13301 allocs/op\nsqlh/model_insert_100_row(s)-8       \t      10\t 125292220 ns/op\t  173843 B/op\t    4100 allocs/op\n# 500 records\ndatabase/sql_insert_500_row(s)-8       \t       2\t 565426900 ns/op\t  677756 B/op\t   18003 allocs/op\nGORM_insert_500_row(s)-8               \t       2\t 650741850 ns/op\t 3347560 B/op\t   47080 allocs/op\nsquirrel_insert_500_row(s)-8           \t       2\t 573679700 ns/op\t 2825428 B/op\t   66529 allocs/op\nsqlh/model_insert_500_row(s)-8       \t       2\t 615725850 ns/op\t  869668 B/op\t   20508 allocs/op\n# 1,000 records\ndatabase/sql_insert_1000_row(s)-8      \t       1\t1163333900 ns/op\t 1357776 B/op\t   36028 allocs/op\nGORM_insert_1000_row(s)-8              \t       1\t1314936200 ns/op\t 6693088 B/op\t   94130 allocs/op\nsquirrel_insert_1000_row(s)-8          \t       1\t1259743000 ns/op\t 5651088 B/op\t  133051 allocs/op\nsqlh/model_insert_1000_row(s)-8      \t       1\t1208060600 ns/op\t 1739528 B/op\t   41015 allocs/op\n```\n\n## Postgres - Insert Slice w/ Begin(), Prepare(), Exec().\nThe following benchmarks show `Begin() -\u003e Prepare() -\u003e Exec()` to insert a slice of `X` records.\n```bash\n# 5 records\ndatabase/sql_begin+prepare+insert_5_row(s)-8            1490\t    736679 ns/op\t    6604 B/op\t     165 allocs/op\nGORM_slice+insert_5_row(s)-8                             950\t   1067537 ns/op\t    9815 B/op\t     143 allocs/op\nsquirrel_begin+prepare+insert_5_row(s)-8                1084\t   1092230 ns/op\t   28024 B/op\t     645 allocs/op\nsqlh/model_begin+prepare+insert_5_row(s)-8               568\t   2596587 ns/op\t    8082 B/op\t     196 allocs/op\n# 50 records\ndatabase/sql_begin+prepare+insert_50_row(s)-8            138\t   8354679 ns/op\t   66298 B/op\t    1652 allocs/op\nGORM_slice+insert_50_row(s)-8                            501\t   2473041 ns/op\t   57312 B/op\t     793 allocs/op\nsquirrel_begin+prepare+insert_50_row(s)-8                127\t  11681451 ns/op\t  280444 B/op\t    6456 allocs/op\nsqlh/model_begin+prepare+insert_50_row(s)-8              122\t  12672856 ns/op\t   67769 B/op\t    1683 allocs/op\n# 100 records\ndatabase/sql_begin+prepare+insert_100_row(s)-8            70\t  24493961 ns/op\t  132531 B/op\t    3304 allocs/op\nGORM_slice+insert_100_row(s)-8                           396\t   2777564 ns/op\t  107026 B/op\t    1597 allocs/op\nsquirrel_begin+prepare+insert_100_row(s)-8                45\t  26156067 ns/op\t  560691 B/op\t   12910 allocs/op\nsqlh/model_begin+prepare+insert_100_row(s)-8              67\t  23372439 ns/op\t  134008 B/op\t    3335 allocs/op\n# 500 records\ndatabase/sql_begin+prepare+insert_500_row(s)-8             9\t 111672778 ns/op\t  664056 B/op\t   16536 allocs/op\nGORM_slice+insert_500_row(s)-8                           139\t   8918647 ns/op\t  583896 B/op\t    8009 allocs/op\nsquirrel_begin+prepare+insert_500_row(s)-8                13\t 113849262 ns/op\t 2802340 B/op\t   64551 allocs/op\nsqlh/model_begin+prepare+insert_500_row(s)-8              14\t  89883943 ns/op\t  663012 B/op\t   16543 allocs/op\n# 1,000 records\ndatabase/sql_begin+prepare+insert_1000_row(s)-8            6\t 176948517 ns/op\t 1324336 B/op\t   33033 allocs/op\nGORM_slice+insert_1000_row(s)-8                           74\t  16430857 ns/op\t 1176609 B/op\t   16018 allocs/op\nsquirrel_begin+prepare+insert_1000_row(s)-8                5\t 227757900 ns/op\t 5601816 B/op\t  129079 allocs/op\nsqlh/model_begin+prepare+insert_1000_row(s)-8              6\t 195512150 ns/op\t 1326716 B/op\t   33074 allocs/op\n```\n\n## Postgres - Dumb Update  \nThe following benchmarks show iterating a set of `X` records and updating them without any database transactions or prepared statements.  Certainly you want to avoid this in your application if possible but there are times where it's what your application will need to do.\n\nResults are fairly consistent with `gorm` being something of an outlier:  \n```bash\n# 5 records\ndatabase/sql_update_5_row(s)-8              482\t   2249577 ns/op\t    6537 B/op\t     165 allocs/op\nGORM_update_5_row(s)-8                      723\t   1735263 ns/op\t   29224 B/op\t     335 allocs/op\nsquirrel_update_5_row(s)-8                  738\t   2463613 ns/op\t   38720 B/op\t     875 allocs/op\nsqlh/model_update_5_row(s)-8                580\t   2557353 ns/op\t    8413 B/op\t     195 allocs/op\n# 50 records\ndatabase/sql_update_50_row(s)-8              74\t  17060749 ns/op\t   65468 B/op\t    1650 allocs/op\nGORM_update_50_row(s)-8                     100\t  12066319 ns/op\t  292367 B/op\t    3352 allocs/op\nsquirrel_update_50_row(s)-8                  62\t  26438821 ns/op\t  387376 B/op\t    8753 allocs/op\nsqlh/model_update_50_row(s)-8                43\t  23284305 ns/op\t   84257 B/op\t    1950 allocs/op\n# 100 records\ndatabase/sql_update_100_row(s)-8             27\t  46719315 ns/op\t  130933 B/op\t    3301 allocs/op\nGORM_update_100_row(s)-8                     61\t  24044793 ns/op\t  584659 B/op\t    6704 allocs/op\nsquirrel_update_100_row(s)-8                 24\t  59805871 ns/op\t  774675 B/op\t   17505 allocs/op\nsqlh/model_update_100_row(s)-8               24\t  54183550 ns/op\t  168450 B/op\t    3901 allocs/op\n# 500 records\ndatabase/sql_update_500_row(s)-8              6\t 213189917 ns/op\t  658580 B/op\t   16997 allocs/op\nGORM_update_500_row(s)-8                     14\t  80748021 ns/op\t 2923198 B/op\t   33519 allocs/op\nsquirrel_update_500_row(s)-8                  4\t 439392025 ns/op\t 3877772 B/op\t   88019 allocs/op\nsqlh/model_update_500_row(s)-8                4\t 267054850 ns/op\t  844580 B/op\t   19752 allocs/op\n# 1,000 records\ndatabase/sql_update_1000_row(s)-8             3\t 466049733 ns/op\t 1321160 B/op\t   34498 allocs/op\nGORM_update_1000_row(s)-8                     7\t 197242614 ns/op\t 5848568 B/op\t   67040 allocs/op\nsquirrel_update_1000_row(s)-8                 2\t 779891850 ns/op\t 7760052 B/op\t  176554 allocs/op\nsqlh/model_update_1000_row(s)-8               3\t 382446033 ns/op\t 1690760 B/op\t   39752 allocs/op\n```\n\n## Postgres - Update Slice w/ Begin(), Prepare(), Exec().\nThe following benchmarks show `Begin() -\u003e Prepare() -\u003e Exec()` to insert a slice of `X` records.\n```bash\n# 5 records\ndatabase/sql_begin+prepare+update_5_row(s)-8         \t    1110\t   1336426 ns/op\t    6895 B/op\t     150 allocs/op\nGORM_update_5_row(s)-8                               \t    3848\t    520668 ns/op\t   14241 B/op\t     162 allocs/op\nsquirrel_begin+prepare+update_5_row(s)-8             \t     841\t   1529204 ns/op\t   38957 B/op\t     855 allocs/op\nsqlh/model_begin+prepare+update_5_row(s)-8                   649\t   2008840 ns/op\t    7885 B/op\t     173 allocs/op\n# 50 records\ndatabase/sql_begin+prepare+update_50_row(s)-8        \t     100\t  10373155 ns/op\t   69153 B/op\t    1501 allocs/op\nGORM_update_50_row(s)-8                              \t     535\t   7558777 ns/op\t  110557 B/op\t     820 allocs/op\nsquirrel_begin+prepare+update_50_row(s)-8            \t      81\t  17105143 ns/op\t  389943 B/op\t    8553 allocs/op\nsqlh/model_begin+prepare+update_50_row(s)-8                   97\t  17899106 ns/op\t   70424 B/op\t    1568 allocs/op\n# 100 records\ndatabase/sql_begin+prepare+update_100_row(s)-8       \t      63\t  19669398 ns/op\t  138172 B/op\t    3001 allocs/op\nGORM_update_100_row(s)-8                             \t     280\t  10390849 ns/op\t  205307 B/op\t    1625 allocs/op\nsquirrel_begin+prepare+update_100_row(s)-8           \t      36\t  28659156 ns/op\t  779430 B/op\t   17104 allocs/op\nsqlh/model_begin+prepare+update_100_row(s)-8                  64\t  21718161 ns/op\t  139811 B/op\t    3119 allocs/op\n# 500 records\ndatabase/sql_begin+prepare+update_500_row(s)-8       \t      12\t  97196517 ns/op\t  695215 B/op\t   15498 allocs/op\nGORM_update_500_row(s)-8                             \t      74\t  21223735 ns/op\t 1006385 B/op\t    8681 allocs/op\nsquirrel_begin+prepare+update_500_row(s)-8           \t      10\t 123098130 ns/op\t 3903352 B/op\t   86021 allocs/op\nsqlh/model_begin+prepare+update_500_row(s)-8                  10\t 135324480 ns/op\t  697669 B/op\t   15767 allocs/op\n# 1,000 records\ndatabase/sql_begin+prepare+update_1000_row(s)-8      \t       7\t 206369114 ns/op\t 1396044 B/op\t   31509 allocs/op\nGORM_update_1000_row(s)-8                            \t      39\t  38828905 ns/op\t 2207693 B/op\t   17690 allocs/op\nsquirrel_begin+prepare+update_1000_row(s)-8          \t       6\t 269227417 ns/op\t 7809578 B/op\t  172543 allocs/op\nsqlh/model_begin+prepare+update_1000_row(s)-8                  6\t 229407333 ns/op\t 1397428 B/op\t   31773 allocs/op\n```\n\nThe previous Postgres tests are now repeated with Sqlite sans `gorm`.\n\n## Sqlite - Dumb Insert  \n```bash\n# 5 records\ndatabase/sql_insert_5_row(s)-8             45\t  29689611 ns/op\t  266493 B/op\t    6923 allocs/op\nsquirrel_insert_5_row(s)-8                 50\t  25831794 ns/op\t  288350 B/op\t    7454 allocs/op\nsqlh/model_insert_5_row(s)-8               51\t  31900388 ns/op\t  268402 B/op\t    6955 allocs/op\n# 50 records\ndatabase/sql_insert_50_row(s)-8             4\t 257990950 ns/op\t 2665130 B/op\t   69301 allocs/op\nsquirrel_insert_50_row(s)-8                 4\t 264287750 ns/op\t 2883536 B/op\t   74554 allocs/op\nsqlh/model_insert_50_row(s)-8               4\t 381673525 ns/op\t 2684044 B/op\t   69550 allocs/op\n# 100 records\ndatabase/sql_insert_100_row(s)-8            2\t 515282400 ns/op\t 5330480 B/op\t  138605 allocs/op\nsquirrel_insert_100_row(s)-8                2\t 514017900 ns/op\t 5766700 B/op\t  149104 allocs/op\nsqlh/model_insert_100_row(s)-8              2\t 779631350 ns/op\t 5368056 B/op\t  139100 allocs/op\n# 500 records\ndatabase/sql_insert_500_row(s)-8            1\t2612650600 ns/op\t26649912 B/op\t  693013 allocs/op\nsquirrel_insert_500_row(s)-8                1\t3168402800 ns/op\t28837584 B/op\t  745552 allocs/op\nsqlh/model_insert_500_row(s)-8              1\t2637685200 ns/op\t26840328 B/op\t  695505 allocs/op\n# 1,000 records\ndatabase/sql_insert_1000_row(s)-8           1\t5907092800 ns/op\t53297856 B/op\t 1386017 allocs/op\nsquirrel_insert_1000_row(s)-8               1\t5839871100 ns/op\t57670072 B/op\t 1491095 allocs/op\nsqlh/model_insert_1000_row(s)-8             1\t5444616300 ns/op\t53682080 B/op\t 1391011 allocs/op\n```\n\n## Sqlite - Insert Slice w/ Begin(), Prepare(), Exec().\n```bash\n# 5 records\ndatabase/sql_begin+prepare+insert_5_row(s)-8        \t1992\t    595825 ns/op\t  269003 B/op\t    6975 allocs/op\nsquirrel_begin+prepare+insert_5_row(s)-8            \t1833\t    623820 ns/op\t  290786 B/op\t    7495 allocs/op\nsqlh/model_begin+prepare+insert_5_row(s)-8               208\t   5671543 ns/op\t  269702 B/op\t    6987 allocs/op\n# 50 records\ndatabase/sql_begin+prepare+insert_50_row(s)-8       \t 214\t   6060468 ns/op\t 2690042 B/op\t   69754 allocs/op\nsquirrel_begin+prepare+insert_50_row(s)-8           \t 192\t   6271936 ns/op\t 2907824 B/op\t   74958 allocs/op\nsqlh/model_begin+prepare+insert_50_row(s)-8              100\t  10821204 ns/op\t 2690489 B/op\t   69763 allocs/op\n# 100 records\ndatabase/sql_begin+prepare+insert_100_row(s)-8      \t 106\t  11184752 ns/op\t 5379689 B/op\t  139505 allocs/op\nsquirrel_begin+prepare+insert_100_row(s)-8          \t  96\t  12460612 ns/op\t 5815093 B/op\t  149910 allocs/op\nsqlh/model_begin+prepare+insert_100_row(s)-8              76\t  16489736 ns/op\t 5380870 B/op\t  139521 allocs/op\n# 500 records\ndatabase/sql_begin+prepare+insert_500_row(s)-8      \t  19\t  57751174 ns/op\t26901126 B/op\t  697553 allocs/op\nsquirrel_begin+prepare+insert_500_row(s)-8          \t  18\t  62421122 ns/op\t29076555 B/op\t  749562 allocs/op\nsqlh/model_begin+prepare+insert_500_row(s)-8              18\t  61375433 ns/op\t26900149 B/op\t  697547 allocs/op\n# 1,000 records\ndatabase/sql_begin+prepare+insert_1000_row(s)-8     \t   9\t 111906267 ns/op\t53799579 B/op\t 1395079 allocs/op\nsquirrel_begin+prepare+insert_1000_row(s)-8         \t   8\t 125255625 ns/op\t58156813 B/op\t 1499166 allocs/op\nsqlh/model_begin+prepare+insert_1000_row(s)-8              9\t 120388589 ns/op\t53796854 B/op\t 1395054 allocs/op\n```\n\n## Sqlite - Dumb Update  \n```bash\n# 5 records\ndatabase/sql_update_5_row(s)-8               10000\t    123116 ns/op\t    4610 B/op\t     175 allocs/op\nsquirrel_update_5_row(s)-8                    5836\t    213105 ns/op\t   37144 B/op\t     935 allocs/op\nsqlh/model_update_5_row(s)-8                  8781\t    131921 ns/op\t    6524 B/op\t     205 allocs/op\n# 50 records\ndatabase/sql_update_50_row(s)-8                988\t   1238107 ns/op\t   46097 B/op\t    1751 allocs/op\nsquirrel_update_50_row(s)-8                    570\t   2128517 ns/op\t  371435 B/op\t    9352 allocs/op\nsqlh/model_update_50_row(s)-8                  906\t   1331060 ns/op\t   65286 B/op\t    2050 allocs/op\n# 100 records\ndatabase/sql_update_100_row(s)-8               483\t   2446387 ns/op\t   92150 B/op\t    3501 allocs/op\nsquirrel_update_100_row(s)-8                   279\t   4267277 ns/op\t  742911 B/op\t   18704 allocs/op\nsqlh/model_update_100_row(s)-8                 457\t   2667099 ns/op\t  130623 B/op\t    4102 allocs/op\n# 500 records\ndatabase/sql_update_500_row(s)-8                97\t  12766361 ns/op\t  466980 B/op\t   18001 allocs/op\nsquirrel_update_500_row(s)-8                    55\t  21336253 ns/op\t 3722212 B/op\t   94011 allocs/op\nsqlh/model_update_500_row(s)-8                  90\t  13257092 ns/op\t  654745 B/op\t   20753 allocs/op\n# 1,000 records\ndatabase/sql_update_1000_row(s)-8               49\t  24498727 ns/op\t  939114 B/op\t   36502 allocs/op\nsquirrel_update_1000_row(s)-8                   27\t  42796267 ns/op\t 7453046 B/op\t  188537 allocs/op\nsqlh/model_update_1000_row(s)-8                 44\t  26776673 ns/op\t 1312121 B/op\t   41767 allocs/op\n```\n\n## Sqlite - Update Slice w/ Begin(), Prepare(), Exec().\n```bash\n# 5 records\ndatabase/sql_begin+prepare+update_5_row(s)-8            9703\t    130129 ns/op\t    5847 B/op\t     190 allocs/op\nsquirrel_begin+prepare+update_5_row(s)-8                5458\t    218285 ns/op\t   38304 B/op\t     945 allocs/op\nsqlh/model_begin+prepare+update_5_row(s)-8              8781\t    136517 ns/op\t    6591 B/op\t     205 allocs/op\n# 50 records\ndatabase/sql_begin+prepare+update_50_row(s)-8            916\t   1297656 ns/op\t   58457 B/op\t    1900 allocs/op\nsquirrel_begin+prepare+update_50_row(s)-8                550\t   2339813 ns/op\t  383147 B/op\t    9453 allocs/op\nsqlh/model_begin+prepare+update_50_row(s)-8              859\t   1350686 ns/op\t   59912 B/op\t    1960 allocs/op\n# 100 records\ndatabase/sql_begin+prepare+update_100_row(s)-8           462\t   2594040 ns/op\t  116932 B/op\t    3801 allocs/op\nsquirrel_begin+prepare+update_100_row(s)-8               277\t   4367517 ns/op\t  766107 B/op\t   18904 allocs/op\nsqlh/model_begin+prepare+update_100_row(s)-8             440\t   2738170 ns/op\t  119264 B/op\t    3912 allocs/op\n# 500 records\ndatabase/sql_begin+prepare+update_500_row(s)-8            91\t  12915989 ns/op\t  590369 B/op\t   19494 allocs/op\nsquirrel_begin+prepare+update_500_row(s)-8                55\t  21805969 ns/op\t 3837766 B/op\t   95006 allocs/op\nsqlh/model_begin+prepare+update_500_row(s)-8              87\t  13552601 ns/op\t  595252 B/op\t   19761 allocs/op\n# 1,000 records\ndatabase/sql_begin+prepare+update_1000_row(s)-8           45\t  25837742 ns/op\t 1186918 B/op\t   39500 allocs/op\nsquirrel_begin+prepare+update_1000_row(s)-8               26\t  43744408 ns/op\t 7684063 B/op\t  190526 allocs/op\nsqlh/model_begin+prepare+update_1000_row(s)-8             43\t  27197272 ns/op\t 1192095 B/op\t   39770 allocs/op\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnofeaturesonlybugs%2Fsqlhbenchmarks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnofeaturesonlybugs%2Fsqlhbenchmarks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnofeaturesonlybugs%2Fsqlhbenchmarks/lists"}