Istilah "skala web" telah dihipnotis baru -baru ini, dan orang -orang juga membuat sistem mereka lebih "domain luas" dengan memperluas arsitektur aplikasi mereka. Tapi apa sebenarnya domain penuh? Atau bagaimana memastikan seluruh domain?
Beban penskalaan yang paling hyped adalah domain yang paling populer. Misalnya, sistem yang mendukung akses pengguna tunggal juga dapat mendukung 10, 100, atau bahkan 1 juta akses pengguna. Idealnya, sistem kami harus tetap "tanpa kewarganegaraan" mungkin. Bahkan jika suatu negara harus ada, itu dapat dikonversi dan ditransmisikan pada terminal pemrosesan jaringan yang berbeda. Ketika beban menjadi hambatan, mungkin tidak ada penundaan. Jadi untuk satu permintaan, dapat diterima untuk memakan waktu 50 hingga 100 milidetik. Ini disebut penskalaan.
Ekstensi berkinerja sama sekali berbeda dalam optimasi domain penuh. Misalnya, algoritma yang memastikan bahwa satu data berhasil diproses juga dapat berhasil memproses 10, 100, atau bahkan 1 juta data. Kompleksitas peristiwa (simbol O besar) adalah deskripsi terbaik terlepas dari apakah jenis metrik ini layak atau tidak. Latensi adalah pembunuh penskalaan kinerja. Anda akan mencoba yang terbaik untuk memproses semua operasi pada mesin yang sama. Ini disebut penskalaan.
Jika pie dapat jatuh dari langit (tentu saja ini tidak mungkin), kita mungkin dapat menggabungkan ekspansi horizontal dan ekspansi vertikal. Namun, hari ini kita hanya akan memperkenalkan cara -cara sederhana berikut untuk meningkatkan efisiensi.
Baik forkjoinpool di Java 7 dan aliran data paralel di Java 8 (paralelstream) bermanfaat untuk pemrosesan paralel. Sangat jelas ketika menggunakan program Java pada prosesor multi-core, karena semua prosesor dapat mengakses memori yang sama.
Oleh karena itu, manfaat mendasar dari pemrosesan paralel ini adalah untuk hampir sepenuhnya menghilangkan latensi dibandingkan dengan penskalaan pada mesin yang berbeda di seluruh jaringan.
Tapi jangan bingung dengan efek pemrosesan paralel! Harap diingat dua poin berikut:
Mengurangi kompleksitas algoritma tidak diragukan lagi merupakan cara paling efektif untuk meningkatkan kinerja. Misalnya, untuk metode instance lookup () hashmap, kompleksitas peristiwa o (1) atau kompleksitas ruang O (1) adalah yang tercepat. Tetapi situasi ini seringkali tidak mungkin, apalagi dengan mudah mencapainya.
Jika Anda tidak dapat mengurangi kompleksitas algoritma, Anda juga dapat meningkatkan kinerja dengan menemukan poin -poin penting dalam algoritma dan peningkatan metode. Misalkan kita memiliki diagram algoritma berikut:
Kompleksitas waktu keseluruhan dari algoritma ini adalah O (n3), dan jika dihitung dalam urutan akses terpisah, juga dapat disimpulkan bahwa kompleksitasnya adalah O (n x o x p). Tapi bagaimanapun, kami akan menemukan beberapa skenario aneh ketika kami menganalisis kode ini:
Tanpa referensi data produksi, kami dapat dengan mudah menarik kesimpulan bahwa kami harus mengoptimalkan "operasi overhead tinggi". Tetapi optimisasi yang kami buat tidak memiliki efek pada produk yang dikirimkan.
Aturan emas yang dioptimalkan tidak lebih dari yang berikut:
Itu saja untuk teori. Dengan asumsi bahwa kami telah menemukan bahwa masalah terjadi di cabang kanan, ada kemungkinan bahwa pemrosesan sederhana dalam produk kehilangan respons karena sejumlah besar waktu (dengan asumsi nilai N, O dan P sangat besar), harap dicatat bahwa kompleksitas waktu cabang kiri yang disebutkan dalam artikel tersebut adalah O (n3). Upaya yang dilakukan di sini tidak dapat diperpanjang, tetapi dapat menghemat waktu untuk pengguna dan menunda peningkatan kinerja yang sulit sampai nanti.
Berikut adalah 10 tips untuk meningkatkan kinerja java:
1. Gunakan StringBuilder
StingBuilder harus digunakan secara default dalam kode Java kami, dan operator + harus dihindari. Mungkin Anda akan memiliki pendapat berbeda tentang gula sintaks dari stringbuilder, seperti:
String x = "a" + args.length + "b";
Akan dikompilasi sebagai:
0 baru java.lang.stringbuilder [16] 3 dup4 ldc <string "a"> [18] 6 Invokespecial java.lang.stringbuilder (java.lang.string) [20] 9 aload_0 [args] 10 arraylength11 invokevirtual java.lang.string. java.lang.stringbuilder [23] 14 ldc <string "b"> [27] 16 Invokevirtual java.lang.stringbuilder.append (java.lang.string): java.lang.stringbuilder [29] 19 Invokevirtual java.Lang. [32] 22 Store_1 [x]
Tapi apa sebenarnya yang terjadi? Apakah Anda perlu menggunakan bagian berikut untuk meningkatkan string selanjutnya?
String x = "a" + args.length + "b"; if (args.length == 1) x = x + args [0];
Sekarang kami telah menggunakan stringbuilder kedua, yang tidak mengkonsumsi memori ekstra di tumpukan, tetapi memberi tekanan pada GC.
StringBuilder x = new StringBuilder ("a"); x.append (args.length); x.append ("b"); if (args.length == 1); x.append (args [0]);Dalam contoh di atas, jika Anda mengandalkan kompiler Java untuk secara implisit menghasilkan instance, efek yang dikompilasi tidak ada hubungannya dengan apakah instance StringBuilder digunakan. Harap diingat: Di cabang NOPE, waktu yang dihabiskan untuk setiap siklus CPU dihabiskan untuk GC atau mengalokasikan ruang default untuk StringBuilder, dan kami membuang -buang waktu.
Secara umum, menggunakan StringBuilder lebih baik daripada menggunakan operator +. Jika memungkinkan, pilih StringBuilder jika Anda perlu meneruskan referensi di beberapa metode, karena String mengkonsumsi sumber daya tambahan. JOOQ menggunakan metode ini saat menghasilkan pernyataan SQL yang kompleks. Hanya satu stringbuilder yang digunakan selama seluruh pass-melalui SQL dari pohon sintaks abstrak.
Yang lebih tragis adalah bahwa jika Anda masih menggunakan StringBuffer, maka gunakan StringBuilder alih -alih StringBuffer. Lagi pula, sebenarnya tidak ada banyak kasus di mana string perlu disinkronkan.
Ekspresi reguler memberi orang kesan bahwa mereka cepat dan mudah. Tetapi menggunakan ekspresi reguler di cabang NOPE akan menjadi keputusan terburuk. Jika Anda harus menggunakan ekspresi reguler dalam kode intensif komputasi, setidaknya cache pola untuk menghindari berulang kali menyusun pola.
Pola akhir statis heavy_regex = pola.compile ("((((x)*y)*z)*");Jika hanya ekspresi reguler sederhana seperti berikut ini digunakan:
String [] bagian = ipaddress.split ("//.");Ini yang terbaik adalah menggunakan array char [] normal atau operasi berbasis indeks. Misalnya, kode berikut dengan keterbacaan yang buruk sebenarnya memainkan peran yang sama.
int panjang = ipaddress.length (); int offset = 0; int bagian = 0; untuk (int i = 0; i <panjang; i ++) {if (i == Panjang - 1 || ipaddress.charat (i+1) == '.') {Bagian [bagian] = ipaddress.substring (offset, i+1);Kode di atas juga menunjukkan bahwa optimasi prematur tidak ada artinya. Meskipun dibandingkan dengan metode split (), kode ini kurang dapat dipelihara.
Tantangan: Bisakah teman pintar menghasilkan algoritma yang lebih cepat?
Ekspresi reguler sangat berguna, tetapi mereka juga harus membayar harga saat digunakan. Terutama ketika Anda berada jauh di dalam cabang tidak, Anda harus menghindari menggunakan ekspresi reguler dengan segala cara. Juga berhati -hatilah terhadap berbagai metode string JDK yang menggunakan ekspresi reguler, seperti string.replaceall () atau string.split (). Anda dapat memilih untuk menggunakan perpustakaan pengembangan yang lebih populer, seperti Apache Commons Lang, untuk melakukan operasi string.
Saran ini tidak berlaku untuk acara -acara umum, tetapi hanya untuk skenario jauh di dalam cabang tidak. Meski begitu, Anda harus memahami sesuatu. Metode penulisan loop format Java 5 sangat nyaman sehingga kita dapat melupakan metode loop internal, seperti:
untuk (nilai string: string) {// lakukan sesuatu yang berguna di sini}Setiap kali kode berjalan ke loop ini, jika variabel string adalah iterable, kode akan secara otomatis membuat instance iterator. Jika Anda menggunakan ArrayList, mesin virtual akan secara otomatis mengalokasikan 3 tipe integer memori ke objek pada heap.
kelas pribadi ITR mengimplementasikan iterator <E> {int kursor; int lastret = -1; int diharapkanmodcount = modcount; // ...Anda juga dapat menggunakan metode loop setara berikut untuk menggantikan loop di atas, hanya "membuang-buang" sepotong operasi plastik di tumpukan, yang cukup hemat biaya.
int size = string.size (); for (int i = 0; i <size; i ++) {nilai string: string.get (i); // Lakukan sesuatu yang berguna di sini}Jika nilai string di loop tidak banyak berubah, Anda juga dapat menggunakan array untuk mengimplementasikan loop.
untuk (nilai string: stringArray) {// lakukan sesuatu yang berguna di sini}Baik dari perspektif bacaan dan penulisan yang mudah, atau dari perspektif desain API, iterator, antarmuka yang dapat diulang dan loop foreach sangat berguna. Tetapi dengan biaya, saat menggunakannya, objek tambahan dibuat pada tumpukan untuk setiap anak loop. Jika loop akan dieksekusi berkali -kali, berhati -hatilah untuk menghindari menghasilkan contoh yang tidak berarti. Yang terbaik adalah menggunakan metode loop pointer dasar untuk mengganti iterator yang disebutkan di atas, antarmuka iterable dan foreach loop.
Beberapa pendapat yang keberatan dengan hal di atas (terutama menggantikan iterator dengan pointer) dibahas di Reddit untuk detailnya.
Beberapa metode mahal. Mengambil cabang NOPE sebagai contoh, kami tidak menyebutkan metode daun yang relevan, tetapi yang ini dapat ditemukan. Misalkan driver JDBC kami perlu mengatasi semua kesulitan untuk menghitung nilai pengembalian hasil resultset.wasnull (). Kerangka kerja SQL yang kami implementasikan mungkin terlihat seperti ini:
if (type == integer.class) {result = (t) wasnull (rs, integer.valueof (rs.getint (index)));} // lalu ... statis final <t> t wasnull (hasil rs, nilai t) melempar sqlexception {return rs.wasnull ()? null: nilai;}Dalam logika di atas, metode resultet.wasnull () dipanggil setiap kali nilai int diperoleh dari set hasil, tetapi metode getInt () didefinisikan sebagai:
Tipe Pengembalian: Nilai Variabel; Jika hasil kueri SQL adalah nol, kembalikan 0.
Jadi cara sederhana dan efektif untuk memperbaikinya adalah sebagai berikut:
final statis <t extends number> t wasnull (hasil rs, nilai t) melempar sqlexception {return (value == null || (value.intvalue () == 0 && rs.wasnull ()))? null: nilai;}Ini mudah.
Metode cache memanggil untuk mengganti metode overhead tinggi pada node daun, atau menghindari panggilan metode overhead tinggi jika konvensi metode memungkinkan.
Di atas memperkenalkan penggunaan sejumlah besar obat generik dalam contoh dari JOOQ, menghasilkan penggunaan byte, kelas pendek, int, dan pembungkus panjang. Tetapi setidaknya obat generik tidak boleh menjadi batasan kode sampai mereka berspesialisasi dalam proyek Java 10 atau Valhalla. Karena dapat diganti dengan metode berikut:
// disimpan di heap integer i = 817598;
... jika Anda menulis dengan cara ini:
// Simpan di stack int i = 817598;
Hal -hal bisa menjadi lebih buruk saat menggunakan array:
// Tiga objek dihasilkan pada heap integer [] i = {1337, 424242};... jika Anda menulis dengan cara ini:
// Hanya satu objek yang dihasilkan pada heap int [] i = {1337, 424242};Ketika kita berada jauh di dalam cabang Nope, kita harus mencoba yang terbaik untuk menghindari penggunaan kelas pengemasan. Kelemahan dari melakukan ini adalah bahwa ia memberi banyak tekanan pada GC. GC akan sangat sibuk untuk menghapus objek yang dihasilkan oleh kelas pengemasan.
Jadi metode optimasi yang efektif adalah menggunakan tipe data dasar, array panjang tetap, dan menggunakan serangkaian variabel split untuk mengidentifikasi posisi objek dalam array.
TROVE4J, yang mengikuti protokol LGPL, adalah perpustakaan kelas Java Collection, yang memberi kita implementasi kinerja yang lebih baik daripada pembentukan array int [].
Pengecualian berikut adalah untuk aturan ini: karena jenis boolean dan byte tidak cukup untuk memungkinkan JDK memberikan metode cache untuk itu. Kita bisa menulis dengan cara ini:
Boolean a1 = true; // ... sintaks gula untuk: boolean a2 = boolean.valueof (true); byte b1 = (byte) 123; // ... sintaks gula untuk: byte b2 = byte.valueof ((byte) 123);
Jenis bilangan bulat dasar lainnya juga memiliki situasi yang sama, seperti char, pendek, int, dan panjang.
Jangan secara otomatis mengotak tipe primitif integer ini saat memanggil konstruktor atau memanggil metode thetype.valueof ().
Juga jangan hubungi konstruktor di kelas pembungkus kecuali Anda ingin mendapatkan instance yang tidak dibuat di tumpukan. Keuntungan dari melakukan ini adalah memberi Anda lelucon besar April Mop untuk kolega Anda.
Tentu saja, jika Anda ingin mengalami perpustakaan fungsi off-heap, meskipun ini mungkin dicampur dengan banyak keputusan strategis, daripada solusi lokal yang paling optimis. Untuk artikel menarik tentang penyimpanan non-heap yang ditulis oleh Peter Lawrey dan Ben Cotton, silakan klik: OpenJDK dan HashMap-Biarkan veteran dengan aman menguasai (penyimpanan non-heap!) Teknik baru.
Saat ini, bahasa pemrograman fungsional seperti Scala mendorong rekursi. Karena rekursi biasanya berarti pengulangan ekor yang dapat didekomposisi menjadi individu yang dioptimalkan secara individual. Akan lebih baik jika bahasa pemrograman yang Anda gunakan dapat mendukungnya. Namun demikian, berhati -hatilah agar sedikit penyesuaian algoritma akan mengubah rekursi ekor menjadi rekursi biasa.
Mudah -mudahan kompiler dapat mendeteksi ini secara otomatis, jika tidak kami akan membuang banyak bingkai tumpukan untuk hal -hal yang dapat dilakukan hanya dengan beberapa variabel lokal.
Tidak ada yang bisa dikatakan di bagian ini, kecuali bahwa iterasi sebanyak mungkin di cabang NOPE, bukan rekursi.
Ketika kita ingin mengulangi peta yang disimpan dalam pasangan nilai kunci, kita harus menemukan alasan yang bagus untuk kode berikut:
untuk (K key k: map.keyset ()) {v value: map.get (key);}Belum lagi metode penulisan berikut:
untuk (entri <k, v> entri: map.entryset ()) {k key = entry.getKey (); v value = entry.getValue ();}Ketika kita menggunakan cabang nope, kita harus menggunakan peta dengan hati -hati. Karena banyak operasi akses yang tampaknya memiliki kompleksitas waktu O (1) sebenarnya terdiri dari serangkaian operasi. Dan akses itu sendiri tidak gratis. Setidaknya, jika Anda harus menggunakan peta, Anda perlu menggunakan metode entriSet () untuk mengulangi! Dengan cara ini, kami hanya ingin mengakses instance peta.Entry.
Ketika perlu untuk mengulangi peta dalam bentuk pasangan nilai kunci, pastikan untuk menggunakan metode entriSet ().
8. Gunakan enumset atau enummap
Dalam beberapa kasus, seperti saat menggunakan peta konfigurasi, kita mungkin tahu sebelumnya nilai kunci yang disimpan di peta. Jika nilai kunci ini sangat kecil, kita harus mempertimbangkan untuk menggunakan enumset atau enummap alih -alih menggunakan hashset atau hashmap yang biasa kita gunakan. Kode berikut memberikan penjelasan yang jelas:
objek transien privat [] vals; public v put (K key, value v) {// ... int index = key.ordinal (); vals [index] = masknull (value); // ...}Implementasi utama dari kode sebelumnya adalah bahwa kami menggunakan array alih -alih tabel hash. Terutama ketika memasukkan nilai -nilai baru ke dalam peta, yang harus Anda lakukan adalah mendapatkan nomor urutan konstan yang dihasilkan oleh kompiler untuk setiap jenis enum. Jika ada konfigurasi peta global (misalnya, hanya satu contoh), ENUMMAP akan mencapai kinerja yang lebih luar biasa daripada hashmap di bawah tekanan meningkatkan kecepatan akses. Alasannya adalah bahwa Enummap menggunakan memori sedikit lebih sedikit dari hashmap, dan hashmap memanggil metode hashcode () dan metode Equals () pada setiap nilai kunci.
Enum dan enummap adalah teman dekat. Ketika kita menggunakan nilai-nilai kunci yang mirip dengan struktur seperti enum, kita harus mempertimbangkan untuk mendeklarasikan nilai-nilai kunci ini sebagai tipe enum dan menggunakannya sebagai kunci enummap.
Jika enummap tidak dapat digunakan, setidaknya metode hashcode () dan equals () harus dioptimalkan. Metode hashcode () yang baik diperlukan karena mencegah panggilan yang tidak perlu ke metode Equals () overhead tinggi.
Dalam struktur warisan setiap kelas, objek sederhana yang mudah diterima. Mari kita lihat bagaimana Jooq's org.jooq.table diimplementasikan?
Metode implementasi hashcode () paling sederhana dan tercepat adalah sebagai berikut:
// Abstraktable Implementasi dasar dari tabel umum: @Overridepublic int hashCode () {// [#1938] dibandingkan dengan bagian Query standar, ini adalah implementasi hashcode () yang lebih efisien. Return name.hashCode ();}Nama adalah nama tabel. Kami bahkan tidak perlu mempertimbangkan skema atau atribut tabel lainnya, karena nama tabel biasanya unik dalam database. Dan nama variabel adalah string, yang dengan sendirinya telah di -cache nilai hashcode ().
Komentar dalam kode ini sangat penting karena abstrak yang diwarisi dari AbstractQueryPart adalah implementasi dasar dari setiap elemen pohon sintaks abstrak. Elemen pohon sintaks abstrak biasa tidak memiliki atribut, sehingga mereka tidak dapat memiliki fantasi tentang mengoptimalkan implementasi metode hashcode (). Metode hashcode () yang ditimpa adalah sebagai berikut:
// AbstractQueryPart General Abstrak Sintaks Tree Implementasi Dasar: @Overridepublic int hashCode () {// Ini adalah implementasi default yang berfungsi. // Subkelas implementasi spesifik harus mengganti metode ini untuk meningkatkan kinerja. return create (). renderinlined (this) .hashcode ();}Dengan kata lain, seluruh alur kerja rendering SQL dipicu untuk menghitung kode hash untuk elemen pohon sintaks abstrak yang normal.
Metode Equals () bahkan lebih menarik:
// Implementasi Dasar dari Tabel Umum AbstractTable: @Overridepublic Boolean Equals (Object That) {if (this == itu) {return true;} // [#2144] sebelum memanggil metode abstractqueryPart.Equals () yang tinggi, // Anda dapat mengetahui lebih awal apakah objek tidak sama. if (instance dari abstraktable) {if (stringutils.equals (name, (((abstraktable <?>) itu) .name)))) {return super.equals (itu);} return false;} return false;}Pertama, jangan gunakan metode Equals () terlalu dini (tidak hanya di NOPE), jika:
Catatan: Jika kita menggunakan instance terlalu dini untuk memeriksa tipe yang kompatibel, kondisi berikut sebenarnya termasuk argumen == null. Saya sudah menjelaskan ini di blog saya sebelumnya, silakan merujuk ke 10 praktik terbaik pengkodean java yang indah.
Setelah perbandingan situasi di atas selesai, kita harus dapat menarik beberapa kesimpulan. Misalnya, metode Table.Equals () dari JOOQ digunakan untuk membandingkan apakah kedua tabelnya sama. Terlepas dari jenis implementasi spesifik, mereka harus memiliki nama bidang yang sama. Misalnya, dua elemen berikut tidak dapat sama:
Jika kita dapat dengan mudah menentukan apakah parameter yang masuk sama dengan instance itu sendiri (ini), kita dapat melepaskan operasi jika hasilnya salah. Jika hasil pengembalian benar, kita dapat menilai lebih lanjut implementasi super kelas induk. Dalam kasus di mana sebagian besar objek dibandingkan tidak sama, kita dapat mengakhiri metode sedini mungkin untuk menghemat waktu eksekusi CPU.
Beberapa objek memiliki kesamaan lebih tinggi daripada yang lain.
Di JOOQ, sebagian besar contoh tabel dihasilkan oleh generator kode JOOQ, dan metode Equals () dari contoh -contoh ini telah dioptimalkan secara mendalam. Lusinan jenis tabel lainnya (tabel turunan), fungsi bernilai tabel, tabel array, tabel bergabung, tabel pivot, ekspresi tabel umum, dll., Pertahankan implementasi dasar metode Equals ().
Akhirnya, ada situasi lain yang dapat diterapkan pada semua bahasa dan bukan hanya Java. Selain itu, cabang NOPE yang kami pelajari sebelumnya juga akan membantu dalam pemahaman dari O (N3) hingga O (n log n).
Sayangnya, banyak programmer menggunakan algoritma lokal sederhana untuk mempertimbangkan masalahnya. Mereka digunakan untuk menyelesaikan masalah selangkah demi selangkah. Ini adalah bentuk "ya/atau" imperatif. Gaya pemrograman ini mudah untuk memodelkan "gambaran yang lebih besar" ketika mengkonversi dari pemrograman imperatif murni ke pemrograman yang berorientasi objek ke pemrograman fungsional, tetapi gaya ini tidak memiliki apa yang hanya ada dalam SQL dan R:
Pemrograman deklaratif.
Di SQL, kita dapat menyatakan efek yang diperlukan untuk database tanpa mempertimbangkan pengaruh algoritma. Basis data dapat mengadopsi algoritma terbaik sesuai dengan tipe data, seperti kendala, kunci, indeks, dll.
Secara teori, pertama -tama kita memiliki ide -ide dasar setelah SQL dan perhitungan relasional. Dalam praktiknya, vendor SQL telah mengimplementasikan optimizer efisien berbasis overhead (pengoptimal berbasis biaya) selama beberapa dekade terakhir. Kemudian dalam versi 2010, kami akhirnya menemukan semua potensi SQL.
Tetapi kami tidak perlu menerapkan SQL menggunakan metode set. Semua bahasa dan perpustakaan mendukung set, koleksi, tas, dan daftar. Manfaat utama menggunakan SET adalah bahwa itu dapat membuat kode kami ringkas dan jelas. Misalnya, metode penulisan berikut:
Someset berpotongan sesaat
Alih-alih
// Metode penulisan sebelumnya dari java 8 set result = hashset baru (); untuk (kandidat objek: someset) jika (someotherset.contains (kandidat)) result.add (kandidat); // bahkan jika java 8 digunakan, itu tidak terlalu membantu.
Beberapa orang mungkin memiliki pendapat berbeda tentang pemrograman fungsional dan Java 8 yang dapat membantu kita menulis algoritma yang lebih sederhana dan lebih sederhana. Tetapi pandangan ini belum tentu benar. Kita dapat mengubah loop Java 7 imperatif menjadi koleksi aliran Java 8, tetapi kami masih menggunakan algoritma yang sama. Tapi ekspresi gaya SQL berbeda:
Someset berpotongan sesaatKode di atas dapat memiliki 1000 implementasi berbeda pada mesin yang berbeda. Apa yang kami pelajari hari ini adalah secara otomatis mengonversi dua set menjadi enumset sebelum memanggil operasi intersect. Bahkan kita dapat melakukan operasi berpotongan paralel tanpa memanggil metode stream.parallel () yang mendasarinya.
Dalam artikel ini, kami membahas optimisasi tentang percabangan tidak. Misalnya, jauh ke dalam algoritma kompleksitas tinggi. Sebagai pengembang JOOQ, kami dengan senang hati mengoptimalkan generasi SQL.
Jooq berada di "bawah rantai makanan" karena ini adalah API terakhir yang disebut oleh program komputer kami ketika meninggalkan JVM dan memasuki DBM. Terletak di bagian bawah rantai makanan berarti bahwa setiap garis membutuhkan waktu ketika dieksekusi di JooQ, jadi saya ingin mengoptimalkannya sesegera mungkin.
Logika bisnis kami mungkin tidak rumit seperti cabang tidak. Namun, kerangka dasarnya mungkin sangat kompleks (kerangka kerja SQL lokal, perpustakaan lokal, dll.). Oleh karena itu, kita perlu mengikuti prinsip -prinsip yang disebutkan hari ini, menggunakan kontrol misi Java atau alat lain untuk memeriksa apakah ada area yang perlu dioptimalkan.
Tautan Asli: Terjemahan Jaxenter: ImportNew.com - Tautan Terjemahan Jalan Selalu di Jalan: http://www.importnew.com/16181.html