Страницы

Поиск по вопросам

пятница, 7 декабря 2018 г.

Случаи указания типа данных в условии цикла

Добрый вечер. Пришел с вопросом. Читал тут книгу, в одном фрагменте было написано, что если я укажу тип данных у переменной в условии функции, то значение переменной будет иметь большую область видимости, чем если бы я указал переменную без типа. То есть без типа переменная будет действовать, пока активен цикл, но с типом данных она будет действовать и на еще одни скобки.
Решил проверить. Написал с int'ом-все сработало. Убрал int-и программа стала использовать значение переменной в цикле во всей программе и по какому-то принципу компилятор его даже изменил, по какому-я не понимаю.
Вопрос: Я некорректно понял инфу из учебника? Да, то как все должно быть на самом деле?
#include using namespace std;
int main() { int done=5; int howmany=3;
for( done=1; done cout<Вывод:
7 7 3


Ответ

Рассмотрим следующую программу
#include
int main() { int done = 5; int howmany = 3;
for ( done = 1; done < howmany; done++ ) { std::cout << done << std::endl; }
std::cout << done << std::endl;
return 0; }
Ее вывод на консоль
1 2 3
В этой программе в блоке кода функции main объявлена переменная done. Сначала эта переменная инициализируется значением 5
int done = 5;
а затем в предложении for ей присваивается значение 1
for ( done = 1; done < howmany; done++ ) ^^^^^^^^
После выхода из цикла эта переменная будет иметь значение 3.
Теперь рассмотрим следующую программу
#include
int main() { int done = 5; int howmany = 3;
for ( int done = 1; done < howmany; done++ ) { std::cout << done << std::endl; }
std::cout << done << std::endl;
return 0; }
Ее вывод на консоль
1 2 5
В этой программе в предложении for объявляется переменная с именем done, совпадающем с именем переменной, объявленной в блоке кода main.
for ( int done = 1; done < howmany; done++ ) ^^^^^^^^^^^^
Эта переменная в предложении for скрывает одноименную переменную с таким же именем, объявленную во внешнем блоке кода. Ее область определения - это тело цикла for. После выхода из цикла данная переменная прекращает свое существование.
Из стандарта C++ (6.5.3 The for statement)
3 If the for-init-statement is a declaration, the scope of the name(s) declared extends to the end of the for statement.
Поэтому последняя строка вывода программы
5
уже выводит на консоль значение переменной done, которая была объявлена до цикла в блоке кода функции main
В общем случае имя, объявленное во внутренней области объявления скрывает такое же имя, объявленное во внешней области объявления
Из стандарта C++ (3.3.10 Name hiding)
1 A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).
Обратите внимание, что есть важное отличие в определении предложения for между C++ и C.
В C++ во второй части предложения for, где записывается условие, также может быть объявление.
Рассмотрите следующую демонстрационную программу
#include
int main() { int done = 5; int howmany = 3;
for ( ; int howmany = done; done-- ) { std::cout << done << std::endl; }
std::cout << '
' << howmany << std::endl;
return 0; }
Ее вывод на консоль
5 4 3 2 1
3

При каждой итерации данного цикла for
for ( ; int howmany = done; done-- ) ^^^^^^^^^^^^^^^^^^
объявляется переменная howmany, которая скрывает переменную с таким же именем, объявленную в функции main. Значение, присвоенное этой переменной, преобразуется к булевскому типу. Если оно равно 0, то условие будет ложным и произойдет выход из цикла.
После цикла выводится уже значение переменной howmany, объявленной в main
Ну, и напоследок пример, когда в предложении for сразу в двух его частях объявляются переменные, которые скрывают одноименные переменные с теми же именами, объявленные в main. После выхода из цикла эти переменные прекращают свое существование, и становятся видимыми переменные, объявленные в main
#include
int main() { int done = 10; int howmany = 20;
for ( int done = 5; int howmany = done; done-- ) { std::cout << done << std::endl; }
std::cout << '
' << done << std::endl; std::cout << howmany << std::endl;
return 0; }
Вывод этой программы на консоль
5 4 3 2 1
10 20

Предложение for в этой программе логически может быть представлено как
{ int done = 5;
Label_repeat: { int howmany = done;
if ( howmany != 0 ) { std::cout << done << std::endl; done--; goto Label_repeat; } else { goto Label_exit; } } } Label_exit: //...

WPF Таблица XAML

Ребят подскажите мне тугому как сделать подобную выгрузку элементов с бд с постраничной или динамической прокруткой данных? Задача: В базе хранятся фотографии и фио студентов. Требуется выводить фотографию и под ней ФИО студента.

Прошу прощения за столь глупый вопрос но для меня это пока очень сложно. Возможно кто подскажет готовый пример. Это было бы проще для меня
На данный момент инф. берется таким способом.


Ответ

Окей, ну давайте напишем как это нужно делать. Попробуем сразу сделать из этого MVVM.
Начнём с модели. Главное — модель должна стараться абстрагировать от нас то, что у неё под капотом. Имея это в виду, организуем её просто как список модельных объектов в памяти. Внешний код не должен от этого зависеть.
Итак:
public class StudentModel { public string Name { get; set; } public Uri ImageUri { get; set; } }
public class StudentListModel { const string uri = "https://www.gravatar.com/avatar/f81585f940e68c3bab934cc6f59c901e?" + "s=328&d=identicon&r=PG";
public IEnumerable GetAllStudents() => Enumerable.Range(0, 200).Select(n => new StudentModel() { Name = $"Student #{n}", ImageUri = new Uri(uri) }); }
Функциональность «получить n-ую страницу» я оставляю на VM, держа в голове, что в реальности у вас вместо IEnumerable будет IQueryable. Если вам хочется сделать репозиторий поверх вашего обращения с базой (например потому, что вы не пользуетесь EF), почему бы и нет.
С моделью покамест всё, впиливать базу сюда уж придётся вам лично. Перейдём к VM.
Для начала, базовый класс для VM. Если вы пользуетесь каким-нибудь MVVM-фреймворком, он у вас уже есть. Если нет, напишем его. Он должен имплементировать INotifyPropertyChanged
class VM : INotifyPropertyChanged { protected bool Set(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false;
field = value; RaisePropertyChanged(propertyName); return true; }
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler PropertyChanged; }
Теперь класс, отвечающий за одного студента. С этим всё просто:
class StudentVM : VM { string name; public string Name { get { return name; } set { Set(ref name, value); } }
Uri imageUri; public Uri ImageUri { get { return imageUri; } set { Set(ref imageUri, value); } }
public StudentVM(string name, Uri uri) { this.name = name; this.imageUri = uri; } }
Если вы пишете в соответствии с трендами, и у вас иммутабельные классы, получится проще:
class StudentVM : VM { public string Name { get; } public Uri ImageUri { get; }
public StudentVM(string name, Uri uri) { this.Name = name; this.ImageUri = uri; } }
Дальше — класс, занимающийся списком студентов. Будем писать его по кускам. Начнём.
class StudentListVM : VM {
Нам нужно свойство, отвечающее за количество страниц. Без него никак. Пишем:
int totalPages; public int TotalPages { get { return totalPages; } private set { if (value < 0) throw new ArgumentException(nameof(TotalPages)); Set(ref totalPages, value); } }
Пока всё просто. Да, наверняка мы захотим ещё показать в UI что-то особое, если у нас нет ни одного студента, поэтому положим вспомогательное свойство:
bool havePages; public bool HavePages { get { return havePages; } private set { Set(ref havePages, value); } }
и не забудем установить его в сеттере TotalPages
private set { if (value < 0) throw new ArgumentException(nameof(TotalPages)); Set(ref totalPages, value); HavePages = totalPages > 0; // <--- добавили }
Следующий пункт — номер текущей страницы. С ним всё то же самое, только проверок в сеттере побольше.
int currentPageNo; public int CurrentPageNo { get { return currentPageNo; } set { if (value < 0) throw new ArgumentException(nameof(CurrentPageNo)); if (value >= TotalPages && HavePages) throw new ArgumentException(nameof(CurrentPageNo)); if (value != 0 && !HavePages) throw new ArgumentException(nameof(CurrentPageNo)); Set(ref currentPageNo, value) } }
Теперь, когда текущая страница поменялась, мы должны вычитать новый список студентов. Это нужно сделать в фоне, не блокируя UI-поток. Добавляем в CurrentPageNo
set { if (value < 0) throw new ArgumentException(nameof(CurrentPageNo)); if (value >= TotalPages && HavePages) throw new ArgumentException(nameof(CurrentPageNo)); if (value != 0 && !HavePages) throw new ArgumentException(nameof(CurrentPageNo)); if (Set(ref currentPageNo, value)) // если изменения были... PopulateCurrentPage().IgnoreResult(); // IgnoreResult напишем позже }
Ещё нужно свойство, хранящее список студентов:
IEnumerable currentPage; public IEnumerable CurrentPage { get { return currentPage; } private set { Set(ref currentPage, value); } }
и код, занимающийся обновлением. Он сложный.
// токен для остановки бегущего обновления CancellationTokenSource populationTaskCts = null; async Task PopulateCurrentPage() { // если старое обновление ещё бежит, отменяем его populationTaskCts?.Cancel(); // начиная с этой точки, старое обновление нам не помешает CurrentPage = null; if (!HavePages) return; using (var cts = new CancellationTokenSource()) { // теперь мы - текущее обновление populationTaskCts = cts; var workPageNo = CurrentPageNo; // может поменяться в процессе
try { // асинхронно получаем модельный список var modelPage = await Task.Run(() => GetStudentsFromModel(workPageNo, cts.Token), cts.Token); if (cts.IsCancellationRequested) return; // создаём VM-объекты в UI-потоке var vmPage = modelPage.Select(p => new StudentVM(p.Name, p.ImageUri)) .ToList(); if (cts.IsCancellationRequested) return; // если мы оказались тут, то мы всё ещё текущее обновление Debug.Assert(workPageNo == CurrentPageNo); CurrentPage = vmPage; // и можем присвоить результат } catch (OperationCanceledException) when (cts.IsCancellationRequested) { // ничего не делаем, нас отменили } finally { // если мы текущее обновление, убираем за собой токен if (cts == populationTaskCts) populationTaskCts = null; // в противном случае там чужой токен, его не трогаем } } }
Нам ещё нужен экземпляр модели и процедура GetStudentsFromModel, которая будет их вычитывать:
StudentListModel model = new StudentListModel();
const int pageSize = 10; IEnumerable GetStudentsFromModel(int pageNo, CancellationToken ct) { // make sure it's materialized on background thread return model.GetAllStudents().Skip(pageNo * pageSize).Take(pageSize).ToList(); }
К ней ещё понадобится (позже) подсчёт количества страниц:
int GetPageCount(CancellationToken ct) { var studentCount = model.GetAllStudents().Count(); return (int)Math.Ceiling((double)studentCount / pageSize); }
Сейчас эти процедуры синхронные, но если ваша модель будет выставлять async-интерфейс (как это делает новый EF), их нужно будет сделать асинхронными.
Далее. Нам нужна команда изменения текущей страницы.
public ICommand RequestPageChange { get; }
И её имплементация: метод, который будет отрабатывать:
void OnPageChangeRequest(int newPage) { if (!HavePages) return; if (newPage < 0 || newPage >= TotalPages) return; // log an error? CurrentPageNo = newPage; }
Привязывать команду к имплементации придётся в конструкторе. Заодно и заведём его:
public StudentListVM() { RequestPageChange = new RelayCommand(OnPageChangeRequest); }
(класс RelayCommand есть практически везде, я приведу его позже).
Да, нам ещё в конструкторе нужно запустить подсчёт количества страниц и первоначальное заполнение:
public StudentListVM() { RequestPageChange = new RelayCommand(OnPageChangeRequest); StartInitialPopulate().IgnoreResult(); }
async Task StartInitialPopulate() { TotalPages = await Task.Run(() => GetPageCount(CancellationToken.None)); currentPageNo = 0; await PopulateCurrentPage(); } }
Кажется, ничего не забыли. Класс получился слишком большой, возможно, имеет смысл разрефакторить его на мелкие куски.
Ещё у нас тут упоминался RelayCommand
public class RelayCommand : ICommand { public RelayCommand(Action onExecute) { OnExecute = onExecute; }
public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) => true; public void Execute(object parameter) => OnExecute((T)parameter);
readonly Action OnExecute; }
и функция IgnoreResult
public static class TaskExtgensions { public static void IgnoreResult(this Task t) { } }
На этом с вью-моделью, кажется, всё, перейдём к представлению.
Вью-модель прикрепляем к представлению, как описано здесь
App.xaml:

App.xaml.cs:
using System.Windows;
using Pages.View; using Pages.VM;
namespace Pages { public partial class App : Application { StudentListVM mainVM = new StudentListVM();
protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); new MainWindow() { DataContext = mainVM }.Show(); } } }
Теперь идём в MainWindow.xaml. Начинаем:

На нашем мок-апе есть явно две области: нижняя маленькая со списком страниц, и верхняя большая с содержимым текущей страницы. Это напрашивается на Grid

Теперь, верхний элемент. Он показывает список элементов, без текущего элемента и всего такого. Так что это ItemsControl

Теперь, как расположены элементы в нём? Они идут не в столбик, а «перетекают» по горизонтали в следующую строку. Отлично, значит, нам нужно установить в ItemsPanel подходящий контейнер:

Как выглядит отдельный элемент? Это не стандартный ToString(), это текст с картинкой. Напишем для этого ItemTemplate

Вроде бы ничего не забыли.

Окей, с таблицей справились, теперь нам нужен список страниц. Откуда его взять? У нас по идее есть только количество страниц, нужно его превратить в список при помощи конвертера. Затем, мы ведь не хотим показывать все страницы? Их может быть очень много. Будем показывать первые страницы, последние страницы и страницы вокруг текущей.
Засучим рукава и вперёд!
Для начала, тип для описания страницы или заполнителя:
enum PageEntryType { Normal, Current, Ellipsis }
struct PageEntry { public int PageNumber { get; } public PageEntryType Type { get; } public PageEntry(int num, PageEntryType type) { PageNumber = num; Type = type; } }
Ну и сам конвертер. Надеюсь, я не напутал с вычислениями.
Нам нужен IMultiValueConverter, потому что у нас два входных значения.
class PageListConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { int currentPage = (int)values[0]; int numberOfPages = (int)values[1]; return RecalcList(currentPage, numberOfPages); }
IEnumerable RecalcList(int currentPage, int numberOfPages) { const int pagesAroundCurrent = 3; // сколько страниц вокруг текущей const int pagesAroundEnd = 2; // сколько страниц по краям
var min = Math.Max(0, currentPage - pagesAroundCurrent); var max = Math.Min(numberOfPages - 1, currentPage + pagesAroundCurrent);
// перекрывается список вокруг текущей страницы со списком у левого края? bool separateLeftEnd = pagesAroundEnd + 1 < min; if (!separateLeftEnd) min = 0;
// перекрывается список вокруг текущей страницы со списком у правого края? bool separateRightEnd = numberOfPages - 1 - pagesAroundEnd - 1 > max; if (!separateRightEnd) max = numberOfPages - 1;
if (separateLeftEnd) { for (int n = 0; n < pagesAroundEnd; n++) yield return new PageEntry(n, PageEntryType.Normal); // между списками разрыв - многоточие yield return new PageEntry(-1, PageEntryType.Ellipsis); }
for (int n = min; n <= max; n++) yield return new PageEntry(n, (n == currentPage) ? PageEntryType.Current : PageEntryType.Normal);
if (separateRightEnd) { // между списками разрыв - многоточие yield return new PageEntry(-1, PageEntryType.Ellipsis); for (int n = numberOfPages - pagesAroundEnd; n < numberOfPages; n++) yield return new PageEntry(n, PageEntryType.Normal); } }
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
Отлично, список у нас есть, теперь его нужно показать. Как показывать список? Возвращаемся к нашему недописанному XAML'у. Нам нужен ItemsControl, как обычно. Кладём его во вторую строку и добавим небольшой маргин.

В ресурсы положим конвертер

а элементы берём из количества страниц и номера текущей, с использованием этого конвертера:

Окей, дальше нам нужно эти элементы расположить по горизонтали. Для этого сгодится StackPanel. Саму панель тоже центрируем:

Теперь отображение каждого элемента списка. У нас есть три варианта отображения: обыкновенная страница показывается в виде ссылки, текущая — без ссылки, но жирным шрифтом, а на месте для многоточия должно появиться многоточие. Выбор из этих трёх вариантов делаем при помощи привязки Visibility блока к значению нашего элемента через конвертер. Конвертер мы напишем позже, он будет делать видимым только один из трёх нужных элементов. Сам конвертер мы добавим в ресурсы ItemsControl'а:

Продолжаем:

Располагаем элементы один на другом, видимым будет только один.

Первый вариант: нормальное отображение. Нам нужна гиперссылка. По нажатию на неё вызовем обработчик из code-behind.

Второй вариант: текущая страница. Вместо ссылки — TextBlock с жирным шрифтом.

Ну и третий вариант — просто многоточие.

Вот и всё с отображением элемента.

Больше в XAML'е делать нечего.

Заимплементируем обработчик клика по ссылке. Он лежит в классе MainWindow
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); }
void OnPageChangeRequest(object sender, RoutedEventArgs e) {
Нам нужно где-то взять команду. Чтобы не лазить по DataContext'у, сделаем простой трюк: привяжем эту команду в свободное свойство. Например, в Tag. (Это мы сделаем потом, снова-таки в XAML'е.)
var command = (ICommand)Tag; // прочитали оттуда команду if (command == null) return;
var hyperlink = (Hyperlink)sender;
Номер страницы можно вытащить из DataContext'а гиперссылки.
var pageNo = ((PageEntry)hyperlink.DataContext).PageNumber; command.Execute(pageNo); } }
Возвращаемся в XAML и дописываем Tag

Последняя недописанная вещь — PageEntryTypeToVisibilityConverter. Он очень простой:
public class PageEntryTypeToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { PageEntryType expectedType = (PageEntryType)parameter; PageEntryType actualType = ((PageEntry)value).Type; return expectedType == actualType ? Visibility.Visible : Visibility.Collapsed; }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
Запускаем и получаем:


Да, а давайте ещё сделаем так, чтобы при пустом списке нам показывалось какое-то разумное сообщение. Это просто. Возвращаемся в XAML и добавляем ещё один элемент во внешний Grid

Но так этот элемент будет виден всегда, а нам нужно только когда страниц нету. Не проблема, привяжемся к свойству HavePages. Нам нужно сконвертировать его в Visibility. Но стандартный BooleanToVisibilityConverter конвертирует не в ту сторону, в которую нам надо, поэтому украдём конвертер отсюда
public class BooleanConverter : IValueConverter { public BooleanConverter(T trueValue, T falseValue) { OnTrue = trueValue; OnFalse = falseValue; }
public T OnTrue { get; set; } public T OnFalse { get; set; }
public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (!(value is bool)) return DependencyProperty.UnsetValue; return ((bool)value) ? OnTrue : OnFalse; }
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
public class BooleanToVisibilityConverter : BooleanConverter { public BooleanToVisibilityConverter() : base(Visibility.Visible, Visibility.Collapsed) {} }
Теперь можно написать так:

Нужно только положить его в ресурсы окна:

Дальнейшее наведение красоты — на вас.

Можете объяснить суть invoke

Есть основной поток, в котором я создаю все Controls в winforms. И есть второй поток, который вызывается через срабатывание события. В результате этого события мне нужно изменить значение DataSource у DataGridView. В результате возникает ошибка, что доступ к контролу пытается получить не основной поток, в котором был создан контрол. Решением является использование методов Invoke\BeginInvoke. Но саму суть я не понимаю этих методов и как их реализовать в коде. В создаваемом втором потоке используется функция доступа к dgv
private void RefreshTables() { try { if(con.State == ConnectionState.Closed) { con.Open(); } sql = "select rowid, * from OpenPos"; adapOpenPos = new SQLiteDataAdapter(sql, con); dsOpenPos = new DataSet(); adapOpenPos.Fill(dsOpenPos); dataGridView1.DataSource = dsOpenPos.Tables[0]; dataGridView1.Columns[0].Visible = false; dataGridView1.Columns[15].Visible = false; dataGridView1.Update(); con.Close();
if (con.State == ConnectionState.Closed) { con.Open(); } sql = "select rowid, * from ClosePos"; adapClosePos = new SQLiteDataAdapter(sql, con); dsClosePos = new DataSet(); adapClosePos.Fill(dsClosePos); dataGridView2.DataSource = dsClosePos.Tables[0]; dataGridView2.Columns[0].Visible = false; dataGridView2.Columns[14].Visible = false; dataGridView2.Update(); con.Close(); } catch (Exception e) { MessageBox.Show(e.Message); } }


Ответ

Суть метода Invoke довольно проста - он принимает делегат и выполняет его в том потоке, в котором был создан элемент управления, у которого вызывается Invoke. Как вы могли заметить, если обращаться к контролам в WinForms не из того потока, в котором они были созданы, будет выброшено исключение. Соответственно, метод Invoke полезен в случаях, когда необходимо работать с контролом из других потоков. Метод BeginInvoke делает то же самое, но асинхронно.
Небольшой пример использования Invoke
private void ButtonInvoke_Click(object sender, EventArgs e) { var myThread = new Thread(ThreadFunction); myThread.Start(); //метод выполняется в другом потоке }
private void ThreadFunction() { Thread.Sleep(1000); Action action = () => listBox1.Items.Add("value"); // Свойство InvokeRequired указывает, нeжно ли обращаться к контролу с помощью Invoke if (InvokeRequired) Invoke(action); else action(); }
Стоит также отметить, что async/await, добавленные в C# 5, позволяют обойтись без Invoke
private async void ButtonAsync_Click(object sender, EventArgs e) { listBox1.Items.Add("first"); await Task.Run(async () => { await Task.Delay(1000); }); // этот код будет продолжен в UI потоке, // и здесь нет необходимости использовать Invoke listBox1.Items.Add("second"); }

Как можно оценить суровость выполненного запроса?

Например, есть некоторый сервис, который время от времени выполняет запросы и нужно определить насколько запрос был "тяжелым".
По каким критериям это можно оценить?
Первое, что пришло на ум- это замерить загрузку процессора на SQL Server до и во время выполнения запроса.
По каким критериям еще можно понять, что запрос оказался тяжелым и мог негавтивно сказаться на работу других пользователей с БД?
Собственно, это нужно для программы балансировки нагрузки, что бы выполнять тяжелые запросы в наиболее подходящее время. Собственно, не помешал бы минимальный пример, как эту статистику можно получить из когда программы.


Ответ

Тяжесть зависит от плана выполнения. План выполнения может меняться в зависимости от статистики по таблицам. Статистика может устаревать и порождать неверные планы. Так что "тяжесть" - величина непостоянная.
Кроме того, в SQL Server есть кэш данных, и запрос, выбирающий данные их кэша, ес-но будет выдавать меньше физических чтений с диска. Поэтому при замерах стоит смотреть на количество логических чтений, а не только на количество физических.
Грубо можно оценить, замерив время и IO напрямую:
SET STATISTICS TIME ON SET STATISTICS IO ON
запрос
Выполнить несколько раз, отбросить максимальное и минимальное значение по CPU, по остальным - взять среднее.
Показатели IO будут зависеть от плана, так что они при последовательных выполнениях не поменяются. Для воспроизведения промаха кэша - почистите его вызовом CHECKPOINT; DBCC DROPCLEANBUFFERS;
Из .NET значения статистики можно получить, выставлением свойства sqlConnection.StatisticsEnabled = true + вызовом sqlConnection.RetrieveStatistics()

Что делать с "плохим" запросом - достаточно обширный вопрос. Минимальный набор действий
пересчитать статистику для используемых таблиц(обязательно, иначе есть шанс бороть несуществующую проблему!) получить свежий план выполнения если план плохой - оптимизировать запрос, индексы или структуру базы
Что точно не стоит делать - это править SQL наугад. Оптимизация SQL - достаточно простой процесс, но при этом нужно точно представлять механизм выполнения запросов SQL Server, иначе можно получить кучу скрытых проблем :)

Что такое стек и куча? [дубликат]

На данный вопрос уже ответили: Представление кучи и стека 3 ответа Я изучаю C# и пытаюсь понять что такое стек и куча. В большинстве примеров, стек подается как массив у которого есть функции push() и pop(). Но это не достаточное объяснение для меня. Вот к примеру, у нас есть функция Calculate()
void Calculate() { int x; int y; object z; }
Какую роль в этом примере играет стек, а какую роль играет куча?


Ответ

Если рассматривать язык c# сам по себе, в отрыве от реализации, то действительно знать о том, что такое "стек" вам нет необходимости.
Но если вы хотите хорошо понимать тот инструмент, которым пользуетесь, то можно посмотреть немного под капот.
Платформа Microsoft .NET использует стековый байт-код Intermediate Language (IL, CIL, MSIL).
То есть код, который вы напишите, будет записан в опкодах этого языка и уже непосредственно его и будет выполнять CRL.
Посмотрим на какой-либо простой код c# и на то, как он записан опкодами:
void Main() { int a = 15; int b = 10; int c = a - b; Console.WriteLine(c); }
IL-код я получил в программе Linqpad, в IL DASM будет такой же:
IL_0000: nop IL_0001: ldc.i4.s 0F IL_0003: stloc.0 // a IL_0004: ldc.i4.s 0A IL_0006: stloc.1 // b IL_0007: ldloc.0 // a IL_0008: ldloc.1 // b IL_0009: sub IL_000A: stloc.2 // c IL_000B: ldloc.2 // c IL_000C: call System.Console.WriteLine IL_0011: nop IL_0012: ret
Что мы видим при наведении мыши на ldc или stloc? Мы видим всплывающие подсказки "pushes int value onto stack" или "pops value from top of stack".

То есть все ваши инструкции на c# оказываются очень тесно связанными со стеком. Даже простые операции типа сложения чисел проходят через стек. И циклы фактически тоже разворачиваются в стековые инструкции.
Это как раз устройство нижележащего этажа для c#. Современные языки программирования достаточно часто используют концепцию стековых машин, c# -- один из них.
PS Если хочется погрузиться в эту тему более основательно, то хорошей отправной точкой может стать статья Введение в MSIL [Кенни Керр, пер. Aquila]

Разбиение числа на цифры независимо от длины

Изучаю java и для практики решаю простенькие логические задачки, типа нахождения счастливого билетика. Часто встречаются задания, где на входе есть n-значное число, и необходимо что-то сделать с цифрами, из которого оно состоит (дан диапазон чисел от 1 до 999, найти, в скольких числах из диапазона встречается цифра 2). Все, что я знаю и умею - это разбивать ни цифры делением:
int a = 123 / 100 = 1 int b = 123 / 10 % 10 = 2 int c = 123 % 100
Остальная часть задачи проверяется условием. Собственно сам вопрос: есть ли в java какой либо метод, позволяющий разбивать число на цифры и не привязываться к его длине? Например, числа, в которых необходимо искать 2 и ммм 13! вводятся с клавиатуры? И длина числа ограничена только типом int.


Ответ

Что-то вы сильно мучаетесь с делением. Берите с конца. Взятие остатка от деления "%" числа на 10, всегда вам даст последнее из его цифр. И в цикл! int a = Integer.MAX_VALUE; StringBuilder s = new StringBuilder(); System.out.println(a); while(a>0) { s.insert(0, a%10); a = a / 10; } System.out.println(s.toString()); Причем навскидку, написать данный алгоритм можно не одним способом, выбирайте, кому как нравится: StringBuilder s = new StringBuilder(); for(int a=Integer.MAX_VALUE; a>0; a/=10) s.insert(0, a%10); System.out.println(s); Так же вам, и только вам, решать записывать цифры подряд, а в конце переворачивать строку, либо сразу писать все в начало строки.

Как будет hash (хеш) по-русски?

Для написания дипломных работ требуют использования только русских слов, а не заимствованных из английского языка. Например нельзя использовать: брандмауэр, логин, браузер. На английском можно только название программ, ОС и т.д. Друзья, есть ли у Вас идеи, как называют хеш (в моем случае хеш пароля) в научной литературе на русском? Я встречал - "дайджест сообщения", но "дайджест" тоже английское слово "digest". Видел перевод "сводка сообщения" в википедии, но никаких материалов, где такое словосочетание используется нет.


Ответ

В ГОСТ Р 34.11-94, начиная прямо с названия, используется слово «хэш» и его производные («хэширование»). Так что с этим словом все в порядке. За исключением вопроса правописания («хэш» или «хеш»). В ГОСТах тут слегка разброд и шатания, два ГОСТа одного года (34.10-94 и 34.11-94; да, первый неактуален, см. далее) использовали разные варианты («хеш» и «хэш» соотв.), в ГОСТ 34.10-2001 уже «хэш.» Так что, скорее всего, через «э», но тут я не уверен. Это, лучше, спросите на gramota.ru :)