-
Notifications
You must be signed in to change notification settings - Fork 65
/
README.md
894 lines (576 loc) · 77 KB
/
README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
# Вопросы про кеширование и базам данных
## Что такое индексы в MySQL, как и для чего их использовать и создавать?
В MySQL индексы представляют собой структуры данных, которые улучшают скорость выполнения операций выборки на таблице за счет создания ссылок, которые позволяют быстро находить строки с заданными значениями в столбцах. Индексы играют важную роль в ускорении операций поиска в базах данных, особенно когда работа идет с большими объемами данных.
### Основные типы индексов
1. Обычные индексы (INDEX):
Создаются для ускорения операций поиска. Они позволяют быстро находить строки, основываясь на значениях индексовированных столбцов.
2. Уникальные индексы (UNIQUE INDEX):
Это индексы, которые запрещают дублирование значений в индексируемом столбце или группе столбцов. Уникальные индексы обеспечивают целостность данных.
3. Первичный ключ (PRIMARY KEY):
Это особый вид уникального индекса. В каждой таблице может быть только один первичный ключ, который однозначно идентифицирует каждую строку в таблице. Он не может содержать NULL значений.
4. Полнотекстовый индекс (FULLTEXT INDEX):
Предназначен для текстового поиска в столбцах формата CHAR, VARCHAR и TEXT. Поддерживает поиск целых слов или фраз.
5. Пространственный индекс (SPATIAL INDEX):
Используется для географических данных и ускоряет запросы, которые выполняют расчеты расстояний и пространственных отношений.
### Зачем использовать индексы
- Ускорение выполнения запросов:
Индексы делают операции выборки быстрее, поскольку минимизируют количество строк, которые необходимо просмотреть, чтобы найти нужные данные.
- Обеспечение ограничения уникальности:
Уникальные индексы гарантируют, что в индексируемом столбце не будет дубликатов, обеспечивая целостность данных.
### Как создать индексы
Индексы можно создавать при создании таблицы или добавлять в уже существующую таблицу с помощью команды CREATE INDEX. Вот несколько примеров:
- Создание индекса при создании таблицы:
```sql
CREATE TABLE Employees (
EmployeeID INT NOT NULL,
LastName VARCHAR(255),
FirstName VARCHAR(255),
DepartmentID INT,
PRIMARY KEY (EmployeeID),
INDEX (LastName)
);
```
- Добавление индекса в существующую таблицу:
```sql
CREATE INDEX idx_lastname ON Employees (LastName);
```
- Создание уникального индекса:
```sql
CREATE UNIQUE INDEX idx_unique_employeeid ON Employees (EmployeeID);
```
- Удаление индекса:
```sql
DROP INDEX idx_lastname ON Employees;
```
### Важные моменты и ограничения
- Переиспользование таблицы:
Индексы занимают дисковое пространство и могут увеличивать время обновления, вставки и удаления данных в таблице, потому что каждый раз приходится обновлять и связанные индексы.
- Планирование:
Избыточные или ненужные индексы могут привести к дополнительным нагрузкам на базу и, следовательно, к снижению производительности. Поэтому важно тщательно планировать и применять только те индексы, которые действительно необходимы для оптимизации запросов.
## Что такое составной индекс, как и для чего их использовать и создавать?
Составной индекс (или композитный индекс) в MySQL — это индекс, который включает несколько столбцов таблицы. Они полезны, когда вы часто выполняете запросы, в которых участвуют несколько столбцов в WHERE, JOIN или ORDER BY конструкциях.
### Зачем использовать составные индексы?
Составные индексы значительно улучшают производительность запросов, так как позволяют базе данных быстро находить строки, соответствующие условиям поиска. Это особенно полезно, если запросы содержат фильтрацию или сортировку по нескольким столбцам одновременно.
### Как создавать составные индексы?
#### Синтаксис создания составного индекса
1. При создании таблицы:
```sql
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
column3 datatype,
...
INDEX index_name (column1, column2, column3)
);
```
2. В существующей таблице:
```sql
CREATE INDEX index_name
ON table_name (column1, column2, column3);
```
### Пример использования составного индекса
Предположим, у нас есть таблица `orders` с колонками `order_date`, `customer_id` и `product_id`. Мы часто выполняем запросы, которые фильтруют данные по всем этим столбцам.
```sql
CREATE TABLE orders (
order_id INT AUTO_INCREMENT PRIMARY KEY,
order_date DATE,
customer_id INT,
product_id INT,
amount DECIMAL(10, 2),
INDEX idx_composite (order_date, customer_id, product_id)
);
```
Теперь, если мы выполняем такой запрос:
```sql
SELECT *
FROM orders
WHERE order_date = '2023-10-01' AND customer_id = 123;
```
Индексы на столбцах `order_date`, `customer_id` и `product_id` помогут MySQL быстрее найти нужные строки.
### Важные моменты
- Порядок столбцов в индексе: Порядок столбцов в составном индексе имеет значение. Запросы могут использовать составной индекс только если они фильтруют данные по столбцам индекса в том же порядке, в котором они были определены в индексе.
- Издержки: Индексы ускоряют чтение, но могут замедлить операции записи (вставка, обновление, удаление), так как индексы должны быть обновлены.
### Пример добавления составного индекса к существующей таблице
```sql
CREATE INDEX idx_composite
ON orders (order_date, customer_id, product_id);
```
## Как использовать индексы в JOIN запросах Mysql?
Рекомендуется всегда создавать индексы на полях, участвующих в `ON` условии при `JOIN`. Это уменьшает количество строк, просматриваемых каждой таблицей, что в свою очередь уменьшает общее время выполнения.
Для проверки использования индексов MySQL можно воспользоваться командой `EXPLAIN`. Она покажет, какие индексы используются для выполнения запроса:
## Что такое частичные индексы, как и для чего их использовать и создавать?
Частичные индексы – это особый вид индексов в реляционных базах данных, которые содержат только подмножество строк таблицы, удовлетворяющих определенному условию. Они позволяют оптимизировать запросы за счет снижения объема индексируемых данных и улучшения производительности за счет сокращения времени на обработку запросов и уменьшения объема занимаемой индексовой памяти.
Как создаются частичные индексы:
Создание частичного индекса включает в себя добавление условия, определяющего, какие строки таблицы должны быть включены в индекс. Это условие задается в конструкции `WHERE` при создании индекса. Пример на языке SQL может выглядеть так:
```sql
CREATE INDEX idx_active_users
ON users (last_login)
WHERE status = 'active';
```
В этом примере создается индекс `idx_active_users` для таблицы `users`, который будет индексировать только те строки, которые соответствуют условию `status = 'active'`.
Как использовать частичные индексы:
1. Улучшение производительности: Частичные индексы сокращают количество данных, которые нужно обрабатывать при выполнении запросов, за счет чего запросы могут выполняться быстрее. Это особенно полезно, когда данные редко изменяются.
2. Экономия места: Индексы занимают место в хранилище, и частичные индексы, обрабатывая только часть таблицы, сокращают объем используемого места по сравнению с полными индексами.
3. Оптимизация специфичных запросов: Частичные индексы полезны для ситуаций, когда к таблице применяются часто используемые запросы с условиями. Например, в системах, отслеживающих активных пользователей, индексация только активных записей может значительно ускорить операции выборки.
Когда использовать частичные индексы:
- Часто встречающееся условие: Если запросы к базе часто фильтруются по одному и тому же условию, создание частичного индекса на основе этого условия может предлагать значительные преимущества.
- Редко обновляемые данные: Частичные индексы наиболее эффективны, когда данные в индексируемом сегменте редко изменяются. Частое обновление данных снижает эффективность индекса из-за потребности в частых перестроениях.
- Большие таблицы: В больших таблицах, где индексация всех данных может быть неоправданной с точки зрения производительности и пространства, частичные индексы позволяют оптимизировать системные ресурсы.
В некоторых сценариях, однако, использование частичных индексов может не принести ожидаемой пользы. Например, если большинство строк таблицы соответствуют условию индексации, частичный индекс может оказаться почти таким же объемным, как и полный индекс, не обеспечивая при этом значительных улучшений производительности. Таким образом, принятие решения о применении частичных индексов должно основываться на анализе паттернов запросов и специфике данных.
## В чем отличия InnoDB и MyISAM?
InnoDB и MyISAM — это два различных механизма хранения данных в MySQL, у каждого из которых есть свои особенности и преимущества. Вот основные отличия между ними:
1. Поддержка транзакций
- InnoDB: Поддерживает транзакции (ACID-соответствие), что важно для обеспечения целостности данных. Включает функции, такие как COMMIT, ROLLBACK и SAVEPOINT.
- MyISAM: Не поддерживает транзакции, это делает его менее устойчивым в случаях сбоев.
2. Блокировка уровней
- InnoDB: Использует блокировку на уровне строки, что позволяет уменьшить конфликты при одновременных операциях и увеличить производительность в многопользовательской среде.
- MyISAM: Использует блокировку на уровне таблицы, что может привести к большей конкуренции и задержкам при доступе к данным.
3. Восстановление данных после сбоев
- InnoDB: Имеет встроенные механизмы для восстановления данных после сбоев, такие как журнал транзакций (redo log) и механизм авто-восстановления.
- MyISAM: Менее устойчивая к сбоям и может потребовать ручного восстановления данных.
4. Производительность
- InnoDB: Может быть медленнее для операций чтения в сравнении с MyISAM из-за дополнительных накладных расходов на поддержание транзакций и блокировок на уровне строк.
- MyISAM: Обычно быстрее для операций чтения и может быть предпочтительным для баз данных, которые в основном используются для чтения, а не для записи.
5. Поддержка внешних ключей
- InnoDB: Поддерживает внешние ключи, что позволяет обеспечивать целостность данных на уровне базы данных.
- MyISAM: Не поддерживает внешний ключи, из-за чего целостность данных должна обеспечиваться на уровне приложения.
6. Ограничения по размеру таблицы
- InnoDB: Может работать с таблицами очень большого размера, хотя при этом может быть ограничено файловой системой и параметрами конфигурации.
- MyISAM: Имеет более жесткие ограничения по размеру таблицы, зависящие от конфигурации системы.
Резюмируя:
- InnoDB рекомендуется использовать для приложений, требующих высокой надежности и поддержки транзакций.
- MyISAM может быть лучшим выбором для приложений, где требуется быстрая работа с чтением данных и нет необходимости в транзакционной целостности.
## Возможен ли JOIN со вложенными запросами, как?
Да, в MySQL возможно использовать `JOIN` с вложенными запросами. Это делается для объединения результатов основного запроса с результатами подзапроса. Вложенные запросы могут использоваться как часть операции `JOIN`, и это может быть полезно в ситуациях, когда вам нужно объединить данные из нескольких таблиц на основе сложных условий.
Вот общий пример того, как это может быть реализовано:
```sql
SELECT main_table.column1, main_table.column2, subquery_table.sub_column1
FROM main_table
JOIN (
SELECT sub_column1, sub_column2
FROM another_table
WHERE condition
) AS subquery_table
ON main_table.id = subquery_table.sub_column2;
```
- `main_table` — это основная таблица, из которой вы хотите извлечь данные.
- Подзапрос в `JOIN` строится на таблице `another_table`, где вы можете использовать условия для выборки данных, которые вам нужны.
- Результаты подзапроса обозначаются как `subquery_table`.
- Основной запрос объединяет `main_table` с результатами подзапроса через `ON` условие, которое определяет, как строки из этих двух наборов данных будут сопоставляться.
При использовании подзапросов в JOIN стоит учитывать производительность, так как сложные подзапросы могут заметно снизить скорость выполнения SQL-запроса.
## Что такое дедлоки (deadlock), почему возникают, как можно недопускать?
Дедлоки (deadlocks) в MySQL — это состояние, возникающее, когда две или более транзакции блокируют друг друга, каждая ожидает снятия блокировки, удерживаемой другой транзакцией. В результате ни одна из транзакций не может продолжить выполнение. Дедлоки чаще всего встречаются в многопользовательских системах, где одновременно выполняется множество транзакций, особенно при высоких уровнях конкурентности.
### Причины возникновения дедлоков
1. Перекрестные блокировки: Это самый типичный случай, когда транзакция A удерживает блокировку одного ресурса и ожидает блокировку другого ресурса, который, в свою очередь, удерживается транзакцией B. В то же время транзакция B ждёт разблокировки ресурса, удерживаемого транзакцией A.
2. Несогласованное использование индексов: Индексы влияют на порядок блокировки строк. Если разные транзакции используют разные индексы для доступа к одному и тому же набору строк, это может привести к дедлокам.
3. Недостаточное покрытие индекса: Отсутствие нужных индексов может вызывать полное сканирование таблицы и, как следствие, блокирование больше строк, чем необходимо, что увеличивает шанс дедлока.
4. Длительные транзакции: Чем дольше сохраняются блокировки, тем выше вероятность возникновения дедлоков. Длительные транзакции могут также увеличивать конкуренцию за ресурсы.
5. Непредсказуемое выполнение запросов: В случаях, когда заявки исполняются с большим разбросом вероятностей (например, вставка данных под разными ключами и конкурентное изменение тех же строк), дедлоки могут быть более склонны к возникновению.
### Как избежать дедлоков
1. Упорядоченное запрашивание ресурсов: Убедитесь, что все транзакции запрашивают ресурсы в одном и том же порядке. Это помогает избежать циклических зависимостей.
2. Использование индексов: Создание необходимых индексов помогает уменьшить количество блокируемых строк и уменьшает вероятность дедлоков.
3. Дробление больших транзакций: Разделение длительных транзакций на более мелкие помогает снизить длительность блокировок и уменьшить вероятность дедлока.
4. Изменение уровня изоляции транзакций: Понижение уровня изоляции может снизить время удержания блокировок. Тем не менее, это может привести к другим проблемам с целостностью данных, таким как грязное чтение.
5. Отказ от ручных блокировок: Старайтесь минимизировать использование эксплицитных блокировок, так как это может увеличить вероятность возникновения дедлоков.
6. Оптимизация запросов: Необходимо оптимизировать SQL-запросы, чтобы они выполнялись быстрее и удерживали блокировки как можно меньше времени.
7. Мониторинг и настройка: Регулярно проверяйте и анализируйте логи о дедлоках, настройте конфигурацию MySQL для лучшего управления конкурентным доступом к данным, например, используя опции вроде `innodb_lock_wait_timeout`.
8. Обработка дедлоков на уровне приложения: Поскольку дедлоки могут быть неизбежны в некоторых случаях, приложение должно быть готово корректно обрабатывать исключения по дедлокам (обычно повторный запуск транзакции).
## Что такое HAVING, что он делает как и зачем его использовать?
`HAVING` — это ключевое слово в SQL, используемое в запросах для фильтрации данных после применения агрегирующих функций, таких как `SUM`, `AVG`, `COUNT`, `MIN`, `MAX` и других. Оно похоже на `WHERE`, однако основное различие состоит в том, что `WHERE` применяется для фильтрации строк данных перед выполнением агрегации, тогда как `HAVING` применяется к агрегированным данным после группировки.
### Зачем использовать HAVING?
Представим ситуацию, где нужно выбрать группы данных, которые удовлетворяют определенным условиям после агрегации. Например, необходимо выбрать все отделы компании, в которых общее количество сотрудников больше 50. В подобных случаях `HAVING` предоставляет возможность применить фильтрацию после выполнения `GROUP BY`.
### Синтаксис
Простейший синтаксис выглядит следующим образом:
```sql
SELECT столбец1, агрегатная_функция(столбец2)
FROM таблица
GROUP BY столбец1
HAVING условие;
```
### Пример использования
Предположим, существует таблица `employees` с колонками `department` и `salary`. Вы хотите вывести те отделы, где средняя зарплата превышает 50000.
```sql
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING avg_salary > 50000;
```
### Пояснение
1. `SELECT` выбирает колонки, которые будут отображены в результате.
2. `AVG(salary)` — агрегатная функция, которая вычисляет среднее значение зарплаты для каждой группы.
3. `FROM employees` указывает таблицу, из которой выбираются данные.
4. `GROUP BY department` группирует строки в наборы, по которым к агрегатным функциям будет применяться расчет.
5. `HAVING avg_salary > 50000` фильтрует результаты так, чтобы остались лишь те группы, в которых средняя зарплата превышает 50000.
## Разница между WHERE и HAVING и можно ли использовать HAVING без группировки данных?
`WHERE` и `HAVING` — это два ключевых слова в SQL, которые используются для фильтрации данных, но применяются на разных этапах обработки запроса.
### Основные различия между WHERE и HAVING
1. Этап фильтрации данных:
- `WHERE` фильтрует строки на раннем этапе до группировки данных. Это означает, что условие `WHERE` применяется к каждой индивидуальной строке данных перед любой агрегацией.
- `HAVING` фильтрует результаты после применения агрегатных функций, то есть после выполнения `GROUP BY`. Условия `HAVING` могут ссылаться на агрегированные значения, что делает его полезным для фильтрации на основе результатов агрегатных операций.
2. Использование с агрегатными функциями:
- В `WHERE` нельзя использовать агрегатные функции. `WHERE` работает с "сырыми" данными.
- `HAVING` специально предназначен для работы с результатами агрегатных функций.
3. Применимость:
- `WHERE` может быть использовано в любом запросе для фильтрации данных по индивидуальным критериям.
- `HAVING` обычно используется в сочетании с `GROUP BY`, но может быть использован и без `GROUP BY`, когда требуется фильтрация результатов агрегатной функции по всей таблице.
### Можно ли использовать HAVING без группировки данных?
Да, `HAVING` можно использовать без `GROUP BY`. В этом случае он будет действовать как дополнительное условие к запросу с агрегатными функциями, применяемыми ко всему набору данных, а не к отдельным группам.
## Что такое EXPLAIN?
Команда `EXPLAIN` в MySQL используется для получения информации о том, как будет выполняться определённый SQL-запрос, особенно `SELECT` запрос. Это мощный инструмент для оптимизации запросов, так как он позволяет понять, каким образом MySQL планирует обработать данные.
Когда вы передаете запрос в `EXPLAIN`, MySQL предоставляет план выполнения, который объясняет, какие таблицы и в каком порядке будут читаться, какие индексы могут быть использованы, как будут соединяться таблицы и прочие детали. Вот основные выходные данные, которые предоставляет команда `EXPLAIN`:
1. id: Указывает номер запроса. Если запрос включает подзапросы, каждая подчасть будет иметь свой собственный ID.
2. select_type: Описывает тип каждого запроса внутри основного запроса, например `SIMPLE`, `PRIMARY`, `UNION`, `SUBQUERY` и т.д.
3. table: Показывает имя таблицы, с которой работает текущая строка плана выполнения.
4. partitions: (В новых версиях) Указывает, какие разделы использует запрос.
5. type: Тип соединения, который используется. Это важнейший параметр для оценки эффективности запроса. Возможные значения от оптимального к менее оптимальному: `system`, `const`, `eq_ref`, `ref`, `range`, `index`, `ALL`.
6. possible_keys: Список индексов, которые могут быть использованы для поиска или сортировки данных.
7. key: Индекс, который фактически используется MySQL для исполнения запроса.
8. key_len: Длина индекса, который MySQL решил использовать.
9. ref: Показывает, какие столбцы или константы сравниваются с индексом.
10. rows: Ориентировочное количество строк, которые MySQL ожидает прочитать для выполнения запроса.
11. filtered: Указывает, какой процент строк после применения условий будут далее обработаны.
12. Extra: Дополнительная информация о том, как MySQL обрабатывает запрос. Например, такие сообщения, как `Using where`, `Using temporary`, `Using filesort`, могут указывать на узкие места в производительности запроса.
Используя `EXPLAIN`, разработчики могут найти и устранить узкие места в запросах, выбирая более эффективные индексы, оптимизируя условия `WHERE` и соединения, а также внося изменения в структуру базы данных или SQL-запросы.
## Как узнать версию Mysql?
1. Через командную строку:
- Подключитесь к серверу MySQL через командную строку:
`mysql -u your_username -p`
- После входа выполните команду:
`SELECT VERSION();`
Это выведет текущую версию MySQL.
2. С помощью команды в терминале (без подключения к MySQL):
- Выполните следующую команду в терминале:
`mysql --version`
- Или
`mysql -V`
Эта команда выведет строку, содержащую информацию о версии MySQL.
3. Через графический интерфейс управления базами данных:
- Если вы используете инструмент управления базами данных, такой как phpMyAdmin или MySQL Workbench, версия MySQL обычно отображается на главной странице или в разделе настроек/о программе.
4. В лог-файлах MySQL:
- Вы также можете проверить лог-файлы MySQL для сообщений, содержащих информацию о версии. Обычно, при запуске сервера MySQL, версия записывается в лог.
## Как можно оптимизировать ORDER BY RAND()?
1. Предварительная выборка: Вместо того, чтобы сортировать весь набор данных, можно сначала выбрать случайные идентификаторы, а затем извлечь соответствующие строки:
```sql
SELECT * FROM table
WHERE id IN (
SELECT id FROM table ORDER BY RAND() LIMIT 100
);
```
Этот метод выбирает вначале 100 случайных строк, а затем извлекает их.
2. Использование временных таблиц: Сначала выберите все идентификаторы в отдельной временной таблице и присвойте случайный индекс, а затем выберите из исходной таблицы, сортируя по этому индексу.
```sql
CREATE TEMPORARY TABLE temp_ids AS
SELECT id FROM table;
SELECT * FROM table
JOIN (
SELECT id FROM temp_ids ORDER BY RAND() LIMIT 100
) AS random_ids
USING (id);
```
3. Лимитированный диапазон: Если вы знаете количество строк в таблице и имеете доступ к первичному ключу, можете случайно выбирать строки по первичным ключам в определенном диапазоне.
```sql
SET @r := (SELECT FLOOR(MAX(id) * RAND()) FROM table);
(SELECT * FROM table WHERE id >= @r LIMIT 1)
UNION
(SELECT * FROM table WHERE id < @r ORDER BY id DESC LIMIT 1);
```
Это подход подходит, если идентификаторы равномерно распределены и не имеют пробелов.
## NULL значения, когда лучше использовать?
В SQL, включая MySQL, значение NULL используется для обозначения отсутствия данных или неопределенного значения в колонке таблицы базы данных. Это значение отличается от нуля (0), пустой строки или любого другого предопределенного значения.
### Когда использовать NULL
1. Отсутствие данных:
Если данные для определенного столбца не были получены или неизвестны в момент вставки записи, то NULL может быть использован для обозначения этого состояния.
2. Опциональные поля:
В случаях, когда поленаполняемость зависит от наличия определенной информации (например, телефон жены или второй адрес), для опциональных полей можно использовать NULL.
3. Динамическое изменение данных:
В ситуациях, когда данные могут быть добавлены позже. Например, дата завершения проекта может остаться NULL, пока проект еще не завершен.
### Концепции работы с NULL
- Сравнения с NULL:
Следует использовать IS NULL или IS NOT NULL в условиях WHERE для фильтрации записей с NULL значениями.
SELECT * FROM employees WHERE manager_id IS NULL;
- Агрегация:
Агрегатные функции часто игнорируют NULL. Например, COUNT(column_name) не включает в подсчет строки, где column_name равен NULL.
- Функции и NULL:
Использование функции COALESCE для предоставления значения по умолчанию, если столбец равен NULL.
SELECT COALESCE(phone_number, 'N/A') FROM contacts;
### Когда избегать NULL
1. Неопределенность:
В случаях, когда наличие NULL может затруднить обработку данных и принятие решений по логическим условиям.
2. Индексы и производительность:
RDBMS (включая MySQL) могут работать медленнее, если в условиях есть проверка на NULL.
3. Бизнес-логика:
Весьма важно оценить влияние NULL на вашу бизнес-логику. Например, если значение всегда известно и важно, лучше использовать значения по умолчанию, чем NULL.
Пример создания таблицы с использованием NULL:
```sql
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100) NOT NULL,
phone VARCHAR(15) NULL
);
```
Здесь phone может быть NULL, если у сотрудника нет телефонного номера.
## Целые числа (TINYINT, SMALLINT, INT, BIGINT) и UNSIGNED, длинна числовых типов?
1. TINYINT:
- Диапазон:
- Знаковый (SIGNED): от -128 до 127
- Беззнаковый (UNSIGNED): от 0 до 255
- Размер: 1 байт
2. SMALLINT:
- Диапазон:
- Знаковый (SIGNED): от -32,768 до 32,767
- Беззнаковый (UNSIGNED): от 0 до 65,535
- Размер: 2 байта
3. INT:
- Диапазон:
- Знаковый (SIGNED): от -2,147,483,648 до 2,147,483,647
- Беззнаковый (UNSIGNED): от 0 до 4,294,967,295
- Размер: 4 байта
4. BIGINT:
- Диапазон:
- Знаковый (SIGNED): от -9,223,372,036,854,775,808 до 9,223,372,036,854,775,807
- Беззнаковый (UNSIGNED): от 0 до 18,446,744,073,709,551,615
- Размер: 8 байт
UNSIGNED:
- Использование ключевого слова UNSIGNED позволяет увеличить максимальное значение целого числа за счет исключения отрицательных значений.
В некоторых случаях может быть указана длина (например, INT(11)), но это не влияет на диапазон значений. Длина используется в основном для отображения, когда значения заполняются нулями слева (например, для ZEROFILL).
Пример создания таблицы с разными типами данных
```sql
CREATE TABLE example_table (
tiny_column TINYINT,
small_column SMALLINT,
int_column INT,
big_column BIGINT,
unsigned_column INT UNSIGNED
);
```
Пример вставки данных
```sql
INSERT INTO example_table (tiny_column, small_column, int_column, big_column, unsigned_column)
VALUES (-128, 32767, 2147483647, 9223372036854775807, 4294967295);
```
## Большие числа: demical, что это и как работает?
Decimal (или DECIMAL) в MySQL — это тип данных, используемый для хранения чисел с фиксированной точностью и масштабом. Он предназначен для случаев, когда важна высокая точность чисел, таких как финансовые расчеты, где результаты должны быть максимально корректными, вплоть до копеек или центов.
### Основные особенности типа DECIMAL
1. Фиксированная точность:
DECIMAL позволяет задать максимальное количество знаков, которые могут быть представлены. Это указывается в формате DECIMAL(M, D), где:
- M — максимальное общее количество цифр (как до, так и после десятичной точки).
- D — количество цифр после десятичной точки.
2. Хранение:
В отличие от типов данных с плавающей точкой (FLOAT и DOUBLE), которые могут иметь погрешности в вычислениях, DECIMAL хранит данные в виде строк (до определенного размера), что позволяет избежать ошибок округления. Это особенно важно в финансовых приложениях, где точное значение имеет критическое значение.
3. Производительность:
DECIMAL может иметь накладные расходы на производительность по сравнению с числами с плавающей точкой, особенно когда выполняются математические операции. Это связано с необходимостью поддержания высокой точности.
4. Использование:
DECIMAL часто используется для хранения валют, налогов и других финансовых значений. Например, можно определить колонку для хранения цен в базах данных интернет-магазина как DECIMAL(10, 2), что позволяет хранить цены с двумя десятичными знаками, максимум до 10 цифр.
5. Округление:
MySQL по умолчанию может округлять результирующие значения при выполнении математических операций, если они превышают допустимый диапазон для заданного DECIMAL(M, D). Это поведение можно контролировать с помощью различных настроек округления.
Пример создания таблицы с использованием DECIMAL:
```sql
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100),
price DECIMAL(10, 2) -- где 10 - общее количество цифр, 2 - количество цифр после запятой
);
```
В этом примере столбец price позволяет хранить значения до 99999999.99. Это обеспечивает точное представление данных с двумя цифрами после запятой, что идеально подходит для отображения цен.
## Float | Double VS Demical, в чем разница, что и как использовать?
1. Float и Double:
- Типы данных: FLOAT и DOUBLE - это типы данных с плавающей точкой.
- Диапазон и точность: FLOAT имеет 32-битное представление с диапазоном от приблизительно 1.18E-38 до 3.4E+38 и точностью до 7 значащих цифр. DOUBLE, с другой стороны, имеет 64-битное представление с диапазоном от приблизительно 2.23E-308 до 1.79E+308 и точностью до 15 значащих цифр.
- Использование: Эти типы данных хорошо подходят для научных вычислений, где нужно оперировать весьма большими или малыми значениями и некоторыми допускаемыми потерями в точности.
2. Decimal:
- Тип данных: DECIMAL (или NUMERIC - синоним в MySQL).
- Диапазон и точность: Этот тип данных хранит числа точно согласно заданному количеству цифр до и после десятичной точки. Например, DECIMAL(10, 2) хранит до 10 цифр, из которых 2 находятся после десятичной точки.
- Использование: DECIMAL используется тогда, когда важна точность вычислений, например, для финансовых приложений, где даже малейшие ошибки в вычислениях не допустимы.
Различия:
- Точность: FLOAT и DOUBLE могут потерять точность при вычислении из-за своей природы. В то время как DECIMAL хранит и обрабатывает данные с точностью, что делает его идеальным для финансовых и других приложений, требующих высокой точности.
- Пространство хранения: FLOAT и DOUBLE занимают меньше места по сравнению с DECIMAL.
Применение в MySQL:
- FLOAT или DOUBLE -- производительность в ущерб точности.
- DECIMAL -- высокая точность в ущерб производительности.
Пример использования:
```sql
CREATE TABLE financials (
id INT PRIMARY KEY,
revenue DECIMAL(15, 2),
expenses DECIMAL(15, 2),
profit DECIMAL(15, 2)
);
CREATE TABLE scientific_data (
id INT PRIMARY KEY,
value FLOAT,
measurement DOUBLE
);
```
В этом примере таблица `financials` использует `DECIMAL` для точных финансовых данных, а таблица `scientific_data` использует `FLOAT` и `DOUBLE` для данных с плавающей точкой.
## Строки VARCHAR и CHAR, отличия когда лучше использовать?
### VARCHAR
- Определение: Этот тип данных хранит строки переменной длины.
- Максимальная длина: Максимальная длина строки, которую можно задать, составляет 65535 символов, но она также зависит от набора символов и других факторов.
- Структура хранения: VARCHAR использует байт для хранения длины строки (или два байта, если длина строки превышает 255 символов), а затем сами данные.
- Особенности: Экономит место для строк переменной длины, так как хранит только не пустое пространство. Более эффективно, если длина строк сильно варьируется.
### CHAR
- Определение: Этот тип данных хранит строки фиксированной длины.
- Максимальная длина: Максимальная длина строки – 255 символов.
- Структура хранения: CHAR всегда хранит строки одинаковой длины, добавляя пробелы до конца строки, если она короче заданной длины.
- Особенности: Лучше использовать для строк, имеющих постоянную длину, так как это может ускорить некоторые операции сравнения и поиска.
Когда лучше использовать:
- VARCHAR:
- Если заранее неизвестна длина данных (например, ввода пользователя).
- Когда строки значительно варьируются по длине.
- Если требуется экономить дисковое пространство.
- CHAR:
- Для строк фиксированной длины (например, коды, идентификаторы, статусы).
- Может быть выгоден для ускорения операций, если все строки одной длины.
Пример:
```sql
CREATE TABLE example (
id INT PRIMARY KEY,
name VARCHAR(100),
status CHAR(1)
);
```
В данном примере `name` использует `VARCHAR`, так как имена могут иметь различную длину, а `status` использует `CHAR` для хранения статуса фиксированной длины в один символ.
## BLOB / TEXT, чем отличаются, как выполнять сортировку по полям данного типа?
В MySQL типы данных BLOB и TEXT используются для хранения больших объемов данных, но имеют некоторые отличия в функциональности и применении.
### Общие характеристики
- Оба типа используются для хранения больших текстовых или бинарных данных.
- Они могут хранить данные размером до несколько гигабайт.
- Оба типа имеют несколько вариаций для различных объемов данных: TINYBLOB/TINYTEXT, BLOB/TEXT, MEDIUMBLOB/MEDIUMTEXT, LONGBLOB/LONGTEXT.
### Отличия между BLOB и TEXT
1. Тип данных:
- BLOB (Binary Large Object): Используется для хранения двоичных данных. Данные хранятся в «сыром» виде, и операции над данными производятся без учета кодировок символов.
- TEXT: Используется для хранения строковых данных. Данные в этих полях учитывают кодировку (например, UTF-8).
2. Сравнение и сортировка:
- BLOB: Сравнивается на основе байтового значения.
- TEXT: Сравнение зависит от кодировки символов и может быть чувствительным к регистру.
3. Индексация:
- Оба типа можно индексировать, но обычно это требует указания префикса фиксированной длины. Поля BLOB и TEXT не могут быть частью полнотекстового индекса. Для индексации в условиях поиска или сортировки обычно ограничивают количество символов через префикс (например, INDEX (column_name(255))).
### Сортировка по полям типа BLOB/TEXT
Сортировка по полям BLOB и TEXT может быть неэффективной из-за их потенциально большого размера. Однако, если сортировка необходима, можно использовать такие подходы:
1. LIMIT: Если возможно, старайтесь ограничивать объем данных для сортировки с помощью LIMIT, сужая диапазон данных для обработки.
2. Применение префикса: Если возможно, используйте индексирование на префиксе строк для более быстрого доступа.
3. Полнотекстовый поиск: Для текстовых данных (TEXT) может быть использован полнотекстовый поиск, который более эффективен в некоторых сценариях, хотя это и не прямая сортировка.
4. Внешние средства сортировки: Если данные слишком большие для эффективной сортировки внутри MySQL, можно рассмотреть возможность сортировки в приложении после выборки данных.
Нужно помнить, что, несмотря на возможности MySQL по работе с большими данными, производительность может сильно ухудшаться при выполнении сложных операций над очень большими полями BLOB и TEXT.
## ENUM, когда может пригодится?
ENUM — это специальный тип данных в MySQL, который позволяет вам задать строго ограниченный набор значений для поля в таблице. Основное его применение — это ситуация, когда вы знаете, что поле будет принимать одно из нескольких заранее определённых значений.
Когда может пригодиться ENUM в MySQL:
1. Ограничение возможных значений: ENUM полезен, когда поле может принимать только фиксированный набор значений, например, статусы заказов (например, 'новый', 'обрабатывается', 'завершён').
2. Увеличение производительности: Поскольку ENUM хранит значения как целочисленные индексы, а не строки, это может уменьшить объём занимаемого пространства и ускорить операции с базой данных.
3. Поддержка данных: ENUM может помочь в поддержании целостности данных, поскольку предотвращает ввод недопустимых значений.
Пример использования ENUM:
```sql
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
status ENUM('новый', 'обрабатывается', 'завершён') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
Вставка данных:
```sql
INSERT INTO orders (status) VALUES ('новый');
INSERT INTO orders (status) VALUES ('обрабатывается');
INSERT INTO orders (status) VALUES ('завершён');
```
Выборка данных:
```sql
SELECT * FROM orders WHERE status = 'новый';
```
Это лишь базовые примеры, но они показывают основные сценарии, в которых ENUM может быть полезен.
## DATETIME / TIMESTAMP, в чем их разница, какие максимальные значения?
DATETIME и TIMESTAMP — это два типа данных в MySQL, которые используются для хранения информации о дате и времени. Несмотря на их схожесть, есть несколько ключевых отличий между ними.
1. Формат хранения:
- DATETIME: хранит дату и время в виде строки в формате `'YYYY-MM-DD HH:MM:SS'`.
- TIMESTAMP: хранит значение в виде 4-байтового целого числа, представляющего количество секунд, прошедших с начала эпохи Unix (1 января 1970 года 00:00:00 UTC).
2. Временная зона:
- DATETIME: не зависит от временной зоны. Значение хранится именно так, как его записали.
- TIMESTAMP: зависит от временной зоны. Значение автоматически конвертируется из текущей временной зоны в UTC при записи в базу и обратно в текущую временную зону при чтении.
3. Диапазон значений:
- DATETIME: может хранить даты от `'1000-01-01 00:00:00'` до `'9999-12-31 23:59:59'`.
- TIMESTAMP: может хранить даты от `'1970-01-01 00:00:01' UTC` до `'2038-01-19 03:14:07'` UTC из-за ограничения на 4-байтовое целое число.
4. Объем памяти:
- DATETIME: занимает 8 байт пространства хранения.
- TIMESTAMP: занимает 4 байта пространства хранения.
### Примеры использования
```sql
CREATE TABLE example (
event_id INT AUTO_INCREMENT PRIMARY KEY,
event_datetime DATETIME,
event_timestamp TIMESTAMP
);
INSERT INTO example (event_datetime, event_timestamp)
VALUES ('2023-10-05 12:34:56', '2023-10-05 12:34:56');
```
- DATETIME, для хранения даты и времени без учета временной зоны или даты вне диапазона TIMESTAMP.
- TIMESTAMP, если важно учитывать временные зоны и хранить дату и время в компактном формате.
## Когда и зачем может пригодиться денормализация данных?
Денормализация данных — это процесс сознательного введения избыточности в базу данных для улучшения производительности и упрощения операций с данными. Она может быть полезна в следующих случаях:
1. Проблемы с производительностью чтения: В нормализованных базах данных данные часто распределены по многим таблицам. Это может требовать сложных операций соединения (JOIN) для получения нужной информации, что может быть дорогостоящим в плане времени. Денормализация снижает количество необходимых JOIN-операций, что ускоряет чтение данных.
2. Оптимизация запросов для отчетности и аналитики: В аналитических системах и системах, требующих быстрого формирования отчетов, денормализация может быть полезной для получения данных из одной таблицы вместо выполнения сложных запросов.
3. Кэширование часто используемых данных: Часто запрашиваемые данные могут быть денормализованы для уменьшения времени отклика. Это позволяет системе быстрее получать доступ к данным без сложных вычислений.
4. Упрощение структуры данных для приложений: В некоторых случаях для упрощения архитектуры приложения и минимизации логики обработки данных на уровне приложения используется денормализация, что позволяет напрямую работать с более простыми структурами данных.
5. Минимизация нагрузки на сервер базы данных: При высоких объемах транзакций денормализация может снизить нагрузку на сервер, так как уменьшает сложность операций чтения.
6. Поддержка исторических данных: В случае, когда необходимо сохранять исторические данные, иногда оказывается проще поддерживать избыточную информацию в виде отдельной денормализованной таблицы.
Тем не менее, денормализация имеет свои недостатки:
- Увеличение избыточности данных: Основной недостаток заключается в увеличении дублирования данных, что может осложнить задачи по обновлению данных и привести к несогласованности.
- Усложнение поддержания целостности данных: Из-за избыточности данных сложнее управлять их целостностью, поскольку приходится обрабатывать больше информации при внесении изменений.
- Затраты на хранение: Денормализованные данные занимают больше места на диске, что может быть значимо в больших объемах данных.
Денормализация является компромиссом между сложностью структуры данных и производительностью. Решение о её использовании должно основываться на анализе требований к производительности конкретной системы, объёмов данных и специфики работы приложений.
## Что такое шардинг и репликация?
Шардинг и репликация — это два различных, но часто взаимодополняющих подхода к управлению данными в базе данных, которые помогают улучшить ее производительность, доступность и масштабируемость.
### Шардинг
Шардинг — это метод горизонтального разделения базы данных на более мелкие, управляемые части, называемые "шардами". Шардинг используется для распределения нагрузки и хранения данных по нескольким серверам или узлам, чтобы увеличить производительность и масштабируемость системы. Каждый шард является отдельной базой данных и хранит только часть общего объема данных.
- Преимущества:
- Масштабируемость: Позволяет обрабатывать большие объемы данных путем распределения на несколько серверов.
- Производительность: Уменьшает нагрузку на отдельные серверы, увеличивая скорость обработки запросов.
- Гибкость: Можно добавлять новые шарды по мере роста объема данных.
- Недостатки:
- Сложность: Более сложная управление и конфигурация.
- Балансировка нагрузки: Требуется постоянное поддержание равномерной загрузки по шардам.
- Целостность данных: Могут возникать сложности с поддержанием транзакционной целостности.
### Репликация
Репликация — это процесс копирования и поддержания копий данных на нескольких серверах или узлах. Цель репликации — повысить доступность и отказоустойчивость базы данных, а также улучшить производительность путём распределения нагрузки на чтение.
- Преимущества:
- Доступность: Обеспечивает высокую доступность данных, так как данные хранятся на нескольких серверах.
- Отказоустойчивость: Если один из серверов выходит из строя, запросы могут обрабатываться другими серверами.
- Производительность: Увеличивает скорость обработки запросов на чтение за счёт распределения нагрузки между несколькими репликами.
- Недостатки:
- Задержки при записи: Из-за необходимости синхронизации данных между серверами.
- Консистентность данных: Возможны проблемы, связанные с временной неконсистентностью данных между серверами при асинхронной репликации.
- Усложнённое управление: Требует дополнительных усилий для настройки и поддержания системы.
## В чем отличие синхронной репликации от асинхронной? Какая подходит лучше для какого кейса?
Синхронная и асинхронная репликации — это два различных метода, используемых для копирования данных между системами или узлами в распределенных системах, таких как базы данных. Каждая из них имеет свои особенности, преимущества и недостатки, которые делают их более подходящими для различных случаев использования.
### Синхронная репликация
Синхронная репликация подразумевает, что все операции записи данных на основном узле должны быть подтверждены и завершены на репликах (вторичных узлах) прежде, чем клиенту сообщат об успешности операции. Это обеспечивает высокий уровень консистентности данных, так как все изменения мгновенно отражаются на всех копиях.
Преимущества:
1. Высокая консистентность: Все данные на репликах всегда актуальны и отражают состояние главного узла в реальном времени.
2. Минимизация риска потери данных: В случае сбоя основного узла данные остаются актуальными на репликах.
Недостатки:
1. Задержка: Из-за необходимости подтверждения записи на всех узлах задержка ответа клиенту может увеличиться.
2. Высокие требования к инфраструктуре: Требуется надежное и быстрое сетевое соединение между узлами для минимизации задержек и обеспечения надежности.
Синхронная репликация подходит для критически важных приложений, где консистентность данных имеет первостепенное значение, например, в банковских системах или других финансовых услугах, где недопустимы расхождения в данных.
### Асинхронная репликация
Асинхронная репликация позволяет основному узлу подтверждать успешное завершение операции клиенту, не дожидаясь, пока данные будут полностью реплицированы на все вторичные узлы. Репликация в данном случае происходит в фоновом режиме.
Преимущества:
1. Низкая задержка для клиентов: Клиенты получают более быстрый отклик, так как не нужно ждать подтверждения от всех реплик.
2. Уменьшенные требования к сети: Можно использовать менее мощную сеть, так как данные реплицируются в фоновом режиме.
Недостатки:
1. Потенциальная несогласованность данных: Изменения могут занять некоторое время, чтобы отразиться на всех репликах, что может привести к несогласованности, особенно в случае сбоя.
2. Риск потери данных: В случае аварии на основном узле, некоторые данные могут не быть сохранены на вторичных узлах, если они еще не были реплицированы.
Асинхронная репликация лучше подходит для приложений, где скорость важнее консистентности, и требуется высокая доступность с минимальными задержками, например, в социальных сетях или новостных порталах.
### Выбор между ними
Выбор между синхронной и асинхронной репликацией зависит от конкретных требований к бизнес-приложению.
- Нужна консистентность и допустимы задержки -- выбираем синхронную репликацию.
- Нужна производительность и доступность с минимальными задержками, а некоторое время допустима несогласованность данных -- выбираем асинхронную репликацию
## Если индекс создан для 2-х колонок и запрос содержит только одну из них - будет ли он работать?
В MySQL, если создан составной (или многоколонный) индекс для двух столбцов, и запрос использует только один из этих столбцов в условии фильтрации, индекс может всё равно использоваться, но с определенными ограничениями.
Когда создаётся составной индекс, MySQL может использовать его для оптимизации запросов при следующих условиях:
1. Левое префиксное правило: Индекс может использоваться, если запрос фильтрует данные по первому столбцу, входящему в состав индекса. Например, если у вас есть составной индекс (column1, column2), и ваш запрос содержит условия по column1, то индекс будет использован.
2. Если фильтрация только по второму столбцу: Если запрос использует в фильтрации только второй столбец (column2), оставляя первый столбец из индекса без фильтрации, то такой индекс чаще всего не будет использован MySQL для улучшения производительности данного запроса.
Рассмотрим пример:
- Индекс создан как (column1, column2).
- Запрос фильтрует WHERE column1 = ...: Индекс используется.
- Запрос фильтрует WHERE column2 = ...: Индекс, скорее всего, не будет использоваться.
- Запрос фильтрует WHERE column1 = ... AND column2 = ...: Индекс будет полностью использован.
Поэтому, для оптимальной работы индексов стоит учесть порядок фильтрации столбцов в запросах, основываясь на порядке следования этих столбцов в составном индексе.